Performance 模式匹配和if-else之间的性能差异
为什么OCaml可以为模式匹配而不是if-else测试生成有效的机器代码 我正在阅读现实世界的OCaml,我遇到了一个部分,他们将模式匹配的性能与if-else测试的性能进行了比较。结果表明,在他们的示例中,模式匹配比if-else测试要快得多。即使代码没有使用if-else测试无法使用的任何特殊模式匹配情况,它也只是比较整数 他们将模式匹配的编译器优化归因于性能差异的原因。编译器将能够根据一组高效选择的运行时检查生成直接跳转到匹配案例的机器代码 我理解这一点,但我不明白为什么编译器不能对if-else测试执行相同的操作。毕竟,代码只是将整数与整数进行比较。这是因为OCaml尚未优化if-else测试,还是因为无法像模式匹配那样优化if-else测试 模式匹配代码如下所示:Performance 模式匹配和if-else之间的性能差异,performance,pattern-matching,ocaml,Performance,Pattern Matching,Ocaml,为什么OCaml可以为模式匹配而不是if-else测试生成有效的机器代码 我正在阅读现实世界的OCaml,我遇到了一个部分,他们将模式匹配的性能与if-else测试的性能进行了比较。结果表明,在他们的示例中,模式匹配比if-else测试要快得多。即使代码没有使用if-else测试无法使用的任何特殊模式匹配情况,它也只是比较整数 他们将模式匹配的编译器优化归因于性能差异的原因。编译器将能够根据一组高效选择的运行时检查生成直接跳转到匹配案例的机器代码 我理解这一点,但我不明白为什么编译器不能对if-
let plus_one_match x =
match x with
| 0 -> 1
| 1 -> 2
| 2 -> 3
| _ -> x + 1
let plus_one_if x =
if x = 0 then 1
else if x = 1 then 2
else if x = 2 then 3
else x + 1
if-else代码如下所示:
let plus_one_match x =
match x with
| 0 -> 1
| 1 -> 2
| 2 -> 3
| _ -> x + 1
let plus_one_if x =
if x = 0 then 1
else if x = 1 then 2
else if x = 2 then 3
else x + 1
当然,可以用同样的方法优化if-else测试。例如,您可以编写一个新的Optimizer,它分两个阶段工作:首先将所有if-else测试转换为可能的模式匹配(仍然在OCaml中),然后运行现有的编译器 因此,答案必须是优化if-else测试在编译器开发人员的优先级列表中并不是很高
由于编译器的未来版本可能会为if-else测试带来更好的优化,我现在只会更改时间关键型代码。
match
和if
具有不同的语义:match
是并行的,if
是严格顺序的。如果你有表达能力:
match expr with
| A -> e1
| B -> e2
| C -> e3
| ...
然后它可以按任何顺序比较分支。在我提供的示例中,它可以编译为二进制搜索,利用构造函数表示为一个oridinary数这一事实
在表达式中
if e1 then e2 else if e3 then e4 else ...
该语言的语义要求在e1
和iffe1
计算为false后严格计算e3
。这意味着,编译器无法重新排列比较顺序,因为它无法知道e1
是否为true
或false
(如果它知道,则with if表达式将使用常量折叠进行修剪,所以这无关紧要)
回到你的例子。如果编译匹配函数,将得到以下代码(在x86_64上):
这实际上对应于以下表达式:
if x > 2 then x + 1
else match compare x 1 with
| 0 -> 2
| 1 -> 3
| _ -> 1
非常高效的代码,它只使用两个比较。在运行时,通常(取决于数据分布)只需一次比较即可完成
如果您使用If
编译一个示例,那么它将发出与原始OCaml代码基本相同的代码。因为,编译器需要这样做,根据if
表达式的语义<代码>如果表达式必须是连续的
有人可能会说,if
示例可以编译成相同的代码,因为比较函数是内置的比较函数。但为此,编译器需要证明,比较函数是内置的,或者没有副作用。在这种情况下,仅适用于带有int
的一种特殊情况。我怀疑,有人会写这样的优化,因为它不值得
match
表达式的另一个显著特征是,可以在一组非常有限的对象上执行匹配,这些对象共享一个共同点,它们都是序号,或者可以排序。在if
表达式中,我们有任意表达式 要进行此优化,您需要证明=
函数没有副作用。即使是内置的=
也有副作用:它会引发异常。当然,可以在优化器中硬编码一个启发式算法,这将假定,对于整数,它永远不会抛出异常。但是其他类型的呢?但我怀疑这是否值得。