OCaml 模块和性能

7

有些函数在OCaml中实现非常容易(例如从列表中的映射),但您可以使用OCaml库的List.map方法:

然而,我们会想知道哪个代码更有效。调用单独编译单元(库)的模块可能会使一些可能的优化失效。我在fa.caml新闻组中读到,当从库调用函数时,会使用闭包。

我有一个使用模块和函数子程序进行通用编程的OCaml代码。由于历史原因,我的代码是单块的:全部在一个文件中。现在我有更多时间,我愿意将代码分成文件以用于这些模块。但是,我担心会降低性能,因为我花了一段时间才弄清楚它。例如,我有用于用数字包装复杂对象的模块,因此我强制实现唯一表示和快速比较。我将这些包装对象与通用地图、集合一起使用,并在其上构建缓存。

问题是:

  • 如果我转移到分离的文件中,我会失去性能吗?
  • OCaml是否对我的充满模块、函数子程序等的代码进行了许多优化?

在C++中,如果在.h文件中定义类方法,编译器可能会内联短方法等。在OCaml中是否可以使用分离的文件实现这一点?


我对OCaml编译器和链接器的内部机制了解不多,所以无法回答你的问题。然而,如果你将代码分成模块,即使失去了一些毫秒级的性能,增加的代码清晰度也是非常值得的。 - A. Levy
在C/C++中,这可能会造成巨大的差异。我有数百万个对象,被访问/比较了无数次。每次访问的一组附加引用可能非常非常糟糕。 - hectorpal
是的,但编译器应该内联这些引用,这样实际上您不会做比必要更多的查找。你可以试着创建一个带有一堆虚拟模块的测试项目,并尝试测量将它们分解和保留在同一个文件中是否有任何差异。这可能比重构您的工作代码库要少得多。希望这能让您更有信心,ocamlopt将能够智能地优化您的代码。 - A. Levy
1个回答

10
您可能会失去一些性能。然而,有两个缓解因素:
  • OCaml本地代码编译器可以进行跨模块内联,因此即使在分离的编译单元中也有可能实现代码内联(有几个注意事项-递归函数和函数参数不会跨模块[1])。
  • 代码很可能仍然足够快,并且可读性和可维护性的收益很可能超过了任何(微小的)性能成本。

我不知道OCaml是否将functors定义在同一源文件中时,对代码进行解嵌套处理。如果没有,则模块不应增加任何已经由functors引起的性能损失。

总的来说,我认为最好编写直观、易读、易于维护的代码,不要过于担心像这样微观的性能特征,除非代码在实践中证明它太慢了。


谢谢Michael。好信息。当然,我知道我会获得可读性。我现在的情况并不令人满意。但是,在我的情况下,运行时性能是一个关键问题。我已经花了很多时间从列表切换到数组(我现在正在使用Res库来增长数组)。我还有大量缓存和精心选择的数据结构。我认为通过做我所做的事情,我已经从10分钟或更糟的情况下降到了10秒钟。我现在主要关注的是包装数百万对象表示的模块。无论如何我都会分割,但我需要评估影响,并且可能不会全部拆分。 - hectorpal
一旦您完成了代码重构,有选择性地将某些模块移回主文件应该相对容易。 - Martin DeMello

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接