ano*_*nol 12 performance f# ocaml
我经常读到异常有点慢,如果性能是一个问题应该避免(例如,在Java,F#等).这是否适用于常见的OCaml函数,例如Hashtbl.find
,返回未找到元素的异常?
特别是,如果我希望我的应用程序有效,我应该总是使用,例如,Hashtable.mem
在调用之前测试元素成员资格Hashtbl.find
吗?或者mem
功能的额外比较是否会对性能产生负面影响?
gas*_*che 20
OCaml异常处理可以非常快速地引发和捕获异常 - 请参阅此SO线程以获取有关其实现方式的内部详细信息.我没有注意精确地对它进行基准测试,但我的随机猜测是它是间接函数调用的大概.
众所周知,与语言的其他部分成比例,OCaml异常明显更快,例如F#的异常 - 这会导致人们将代码从OCaml移植到F#的性能问题.在OCaml中,异常不会导致性能问题.
Hashtbl.mem
之前的调用Hashtbl.find
可能比捕获异常要慢.惯用的风格往往是try Hashtbl.find .. with Not_found -> ...
.
也就是说,OCaml社区中有一个明智的运动,使用更明确的错误处理方式,使用option
类型而不是异常.理由不是基于性能,而是基于类型检查器然后阻止您忘记处理错误情况的事实.我更喜欢在设计一个全新的API时.使用引发异常的第三方函数时,请确保立即捕获所有可能的异常; 否则就是一种设计气味,应该非常合理.
由于它们的便利性,OCaml异常通常也被用作纯粹的控制流机制(并不表示罕见的故障情况).你会遇到如下代码:
try
for i = 0 to .... do
if .. then raise Exit
done; false
with Exit -> true
Run Code Online (Sandbox Code Playgroud)
最后,我觉得你可能会采取一种糟糕的方法来实现选择.询问关于表演的一般微观问题通常不是要走的路.首先考虑正确性和可读性.性能问题通常应该在稍后进行,并且仅在可测量/可分析的情况下.
首先回答Hashtbl.mem
之前的具体问题Hashtbl.find
:不要这样做,因为检查表中元素是否存在必须不要两次; 虽然两种策略的成本都是O(1),但Hashtbl.mem
首先调用会计算哈希值和查找两次 - 这可能比获取异常需要更长的时间.
作为一般建议,只有在异常概率较低时才创建引发异常的函数.类型系统不考虑异常,因此更强大的实现将具有'a option
返回值而不是'a
可能的异常.该ocaml的核心库使用的后缀_exn
以明确的功能可能会抛出异常,但通常更喜欢非异常抛出的.
所以对于散列表你应该(在一个完美的世界中)有两个函数:
Hashtbl.find_exn : 'a t -> key -> 'a (* throws Not_found *)
Hashtbl.find : 'a t -> key -> 'a option
如有疑问,请使用第二个.如果它不是纯粹的速度,你可以在原始的哈希表周围编写一个简单的包装器:
find_safe h k = try Some (Hashtbl.find h k) with Not_found -> None