我有一个小型测试框架。它执行一个循环,执行以下操作:
runhaskell
执行此操作.该程序生成各种磁盘文件。 这种情况发生了几十次。原来
runhaskell
占用了程序绝大部分的执行时间。一方面,
runhaskell
设法从磁盘加载文件,对其进行标记,对其进行解析,进行依赖性分析,从磁盘加载 20KB 以上的文本,标记并解析所有这些,执行完整的类型推断,检查类型,对核心进行脱糖,链接编译的机器代码,并在解释器中执行该操作,所有时间都在 2 秒的墙上时间之内,当您考虑它时,实际上非常令人印象深刻。另一方面,我仍然想让它走得更快。 ;-)编译测试器(运行上述循环的程序)产生了微小的性能差异。编译脚本链接的 20KB 库代码产生了相当显着的改进。但是每次调用
runhaskell
仍然需要大约 1 秒.生成的 Haskell 文件每个都刚刚超过 1KB,但实际上只有文件的一部分发生了变化。也许编译文件并使用 GHC 的
-e
切换会更快吗?或者,也许是重复创建和销毁许多操作系统进程的开销减慢了速度?每次调用
runhaskell
大概会导致操作系统探索系统搜索路径,找到必要的二进制文件,将其加载到内存中(肯定这已经在磁盘缓存中?),将其链接到任何 DLL,然后启动它。有什么方法可以(轻松)保持 GHC 的一个实例运行,而不必不断创建和销毁操作系统进程?最终,我想总会有 GHC API。但据我了解,这非常难以使用,高度无证,并且在 GHC 的每个小版本发布时都容易发生根本性的变化。我试图执行的任务非常简单,所以我真的不想让事情变得比必要的更复杂。
建议?
更新:切换到
GHC -e
(即,现在除了正在执行的一个表达式之外的所有内容都已编译)没有可测量的性能差异。在这一点上似乎很清楚,这都是操作系统开销。我想知道我是否可以创建一个从测试仪到 GHCi 的管道,从而只使用一个操作系统进程......
最佳答案
好的,我有一个解决方案:我创建了一个 GHCi 进程并连接了它的 stdin
到管道,以便我可以将表达式发送到交互式评估。
后来进行了几次相当大的程序重构,整个测试套件现在大约需要 8 秒来执行,而不是 48 秒。这对我有用! :-D
(对于其他尝试这样做的人:看在上帝的份上,记得将 -v0
切换到 GHCi,否则您会收到 GHCi 欢迎横幅!奇怪的是,如果您以交互方式运行 GHCi,即使使用 -v0
命令提示符仍然出现,但是当连接到管道时,命令提示符消失了;我认为这是一个有用的设计功能,而不是随机事故。)
当然,我走这条奇怪路线的一半原因是我想捕获stdout
和 stderr
到一个文件。使用 RunHaskell
,这很容易;只需在创建子进程时传递适当的选项。但是现在所有的测试用例都由单个操作系统进程运行,所以没有明显的方法来重定向 stdin
和 stdout
.
我想出的解决方案是将所有测试输出定向到单个文件,并且在测试之间让 GHCi 打印出一个魔术字符串(我希望!)不会出现在测试输出中。然后退出 GHCi,下载文件,然后寻找魔法字符串,这样我就可以将文件剪切成合适的 block 。
关于haskell - 加速 runhaskell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9326097/