Performance 异常的OCaml性能

Performance 异常的OCaml性能,performance,f#,ocaml,Performance,F#,Ocaml,我经常读到,异常有点慢,如果性能有问题,应该避免异常(例如,在Java、F#等中)。这是否适用于常见的OCaml函数,例如Hashtbl.find,它为未找到的元素返回异常 特别是,如果我希望我的应用程序是高效的,我是否应该在调用Hashtbl.find之前总是使用Hashtable.mem测试元素成员资格?或者对mem函数的额外比较会对性能产生负面影响吗?首先回答Hashtbl.mem之前的具体问题Hashtbl.find: 不要这样做,因为必须检查表中元素的存在性两次;虽然这两种策略的代价都

我经常读到,异常有点慢,如果性能有问题,应该避免异常(例如,在Java、F#等中)。这是否适用于常见的OCaml函数,例如
Hashtbl.find
,它为未找到的元素返回异常


特别是,如果我希望我的应用程序是高效的,我是否应该在调用
Hashtbl.find
之前总是使用
Hashtable.mem
测试元素成员资格?或者对
mem
函数的额外比较会对性能产生负面影响吗?

首先回答
Hashtbl.mem
之前的具体问题
Hashtbl.find
: 不要这样做,因为必须检查表中元素的存在性两次;虽然这两种策略的代价都是O(1),但首先调用
Hashtbl.mem
将计算两次哈希值和查找,这可能比获取异常花费更长的时间

一般建议,仅在异常概率较低时创建引发异常的函数。类型系统不考虑异常,因此更健壮的实现将有一个
'a选项
返回值,而不是
'a
加上一个可能的异常。ocaml核心库使用后缀
\u exn
来明确函数可能引发异常,但通常更喜欢非异常引发的异常

因此,对于哈希表,您(在理想情况下)应该有两个函数:

Hashtbl.find\u exn:'a t->key->'a(*抛出Not\u found*)

Hashtbl.find:'a t->key->'a选项

如果有疑问,请使用第二个。如果不是为了纯粹的速度,您可以围绕原始哈希表编写一个简单的包装器:


find_safe hk=使用Not_found->None尝试一些(Hashtbl.find hk)
OCaml异常处理使异常的引发和捕获速度非常快--有关如何实现的内部详细信息,请参阅。我没有注意精确地对它进行基准测试,但我随机猜测它在间接函数调用的范围内

众所周知,与语言的其他部分相比,OCaml异常的速度明显快于F#的异常,例如,这就给将代码从OCaml移植到F#带来了性能问题。在OCaml中,异常不会导致性能问题

Hashtbl.find
之前调用
Hashtbl.mem
可能比捕获异常要慢。惯用的风格往往是
try Hashtbl.find。。未找到->…

这就是说,OCaml社区中有一种明智的做法,即使用更明确的错误处理风格,使用
选项
类型而不是异常。其基本原理不是基于性能,而是基于这样一个事实,即类型检查器会阻止您忘记处理错误情况。在设计新的API时,我更喜欢这样。当使用引发异常的第三方函数时,确保立即捕获所有可能的异常;这样做通常是一种设计风格,应该有充分的理由

由于其方便性,OCaml异常也经常被用作纯控制流机制(而不是表示罕见的故障情况)。您将遇到以下代码:

try
  for i = 0 to .... do
    if .. then raise Exit
  done; false
with Exit -> true
最后,我觉得您可能对实现选择采取了一种不好的方法。问一些关于表演的一般性的微观问题通常不是一个好办法。首先考虑正确性和可读性。绩效问题通常应在稍后提出,且仅在可测量/可盈利的情况下提出

我经常读到,异常有点慢,如果性能有问题,应该避免异常(例如,在Java、F#等中)。这是否适用于常见的OCaml函数,例如Hashtbl.find,它为未找到的元素返回异常

不。主流语言中关于异常缓慢和异常情况的民间传说是毫无意义的。异常只是另一个控制流构造。OCaml的异常速度很快,通常用于非异常情况。最后我看(几年前)异常在OCAM中比C++快6X左右,比java快100X左右,比.net快。
人们有时会避免OCaml中的异常,这不是因为性能相关的原因,而是因为他们想要显式的本地控制流,通常会强制调用方对成功/失败联合类型进行匹配,而不是潜在的非本地异常传播。他们这样做是为了提高正确性,这比性能更重要。

您的回答非常合理,但我强烈反对“只有……在异常发生概率较低时提出异常”的想法。概率问题既不是出于性能考虑(引发异常通常是良好的性能方面),也不是出于正确性考虑(低概率错误仍然是错误)。我不明白它在OCaml的上下文中来自何处。您必须考虑位置和错误捕获代码:如果这是一个严重错误,您可能希望放弃当前的计算,例如通知用户。如果您想摆脱一系列函数,这是非常乏味的,因为您必须将错误处理集成到其中的每一个函数中,而不仅仅是一个try/with块。如果您通常预期某件事情会“出错”,您将在本地处理该错误(例如,过滤结果)。您可能只在OCaml中看到过它,因为大多数语言都缺少特殊选项类型,也没有异常的松散类型安全性。我不确定您的(合理的)注释与前面的“低概率”参数有何关系。您是否在“低概率”和“您不能在本地处理并且应该向客户报告的错误”之间建立了隐式联系