模式匹配和 if-else 之间的性能差异

2024-01-15

为什么 OCaml 可以为模式匹配生成高效的机器代码,而不是为 if-else 测试生成高效的机器代码?

我在读 Real World OCaml 时发现this https://realworldocaml.org/v1/en/html/lists-and-patterns.html#performance他们将模式匹配的性能与 if-else 测试的性能进行了比较。事实证明,他们的示例中的模式匹配比 if-else 测试要快得多。尽管代码没有使用任何 if-else 测试不可能实现的特殊模式匹配情况,但它只是比较整数。

他们将模式匹配的编译器优化归因于性能差异的原因。编译器将能够生成机器代码,根据一组有效选择的运行时检查直接跳转到匹配的情况。

我理解这一点,但我真的不明白为什么编译器不能对 if-else 测试做同样的事情。毕竟,代码只是将整数与整数进行比较。这是因为 OCaml 尚未优化 if-else 测试,还是因为不可能像模式匹配那样优化 if-else 测试?

模式匹配代码如下所示:

let plus_one_match x =
    match x with
    | 0 -> 1
    | 1 -> 2
    | 2 -> 3
    | _ -> x + 1

if-else 代码如下所示:

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

match and if具有不同的语义:match是平行的,if是严格顺序的。如果你有表情:

 match expr with
 | A -> e1
 | B -> e2
 | C -> e3
 | ...

然后它可以按任何顺序比较分支。在我提供的示例中,它可以编译为二分搜索,利用构造函数表示为普通数字的事实。

在表达式中

if e1 then e2 else if e3 then e4 else ...

这是语言语义所要求的,即e3经过严格评估后e1和当且仅当e1被评估为 false。这意味着,编译器无法重新排列比较顺序,因为它不知道是否e1 is true of false(如果它知道,那么 if 表达式将通过常量折叠进行修剪,所以没关系)。

回到你的例子。如果编译您的匹配函数,您将得到以下代码(在 x86_64 上):

.L104:
    cmpq    $5, %rax
    jbe .L103
    addq    $2, %rax
    ret
.L103:
    sarq    $1, %rax
    cmpq    $1, %rax
    je  .L101
    jg  .L100
.L102:
    movq    $3, %rax
    ret
.L101:
    movq    $5, %rax
    ret
.L100:
    movq    $7, %rax
    ret

这实际上对应于表达式:

if x > 2 then x + 1 
else match compare x 1 with 
| 0 -> 2
| 1 -> 3
| _ -> 1

非常高效的代码,只使用两次比较。在运行时,它通常(取决于数据分布)以一次比较结束。

如果你编译一个例子if然后它会发出基本上等于原始 OCaml 代码的代码。因为,根据语义,编译器需要这样做if表达。if表达must是连续的。

人们可以争辩说,if例如,假设比较函数是内置比较函数,则可以编译为相同的代码。但为此,编译器需要证明比较函数是内置的或没有副作用。仅针对一种特定情况int。我怀疑有人会编写这样的优化,因为它不值得。

其他显着特征match表达式的特点是匹配可以在一组非常有限的对象上执行,这些对象有一个共同点,它们都是序数,或者可以排序。在if表达式,我们有任意表达式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模式匹配和 if-else 之间的性能差异 的相关文章

  • 当我在 MySQL 中使用 UUID 作为主键时,会如何影响性能

    我想知道当我在 MySQL 中使用 UUID 作为主键时 会对服务器的性能产生怎样或多大的影响 我想你正在使用InnoDB 无论如何你应该 因此 请阅读 高性能 MySQL 2ed 第 117 页中的以下章节 一般来说 从性能的角度来看 U
  • matplotlib savefig 性能,在循环内保存多个 png

    我希望找到一种方法来优化以下情况 我有一个使用 matplotlib 的 imshow 创建的大型等高线图 然后 我想使用此等高线图来创建大量 png 图像 其中通过更改 x 和 y 限制以及长宽比 每个图像都是等高线图像的一小部分 因此
  • 需要更快的数组复制

    经过一些阅读后 我发现在 java 中复制数组的方式存在一些差异 对于我的应用程序 我有一个递归节点树 每个节点都包含一个 2d 板数组 8x8 通过探查器测试 我能想到的最好的办法是 java util Arrays copyOf arr
  • 快速 HTML 表格排序?

    是的 我知道有一个lot有很多 JS jQuery 程序可以做到这一点 我目前正在使用http www kryogenix org code browser sorttable sorttable js http www kryogenix
  • 在 Chrome 18 中检测 SwiftShader WebGL 渲染器

    我有一个 2D HTML5 游戏引擎 www scirra com http www scirra com 并且确实想检测 WebGL 是否将使用 Chrome 18 的 Swiftshader 软件渲染器进行渲染 如果是这样我们会much
  • php 日期函数和 Carbon 哪个更快?

    Carbon 是 DateTime 的简单 PHP API 扩展 我想知道我们可以通过 Composer 安装 Carbon 来使用日期时间函数 php 日期时间函数和 Carbon 哪个更快 我对您的评论做了一些测试 比较了 DateTi
  • Mysql:多个表还是一张大表?

    这个问题已经被问过 但我还没有找到 1 个语音答案 最好这样做 1 张大桌子 其中 用户 ID 属性 1 属性 2 属性 3 属性 4 或 4 个小桌子 其中 用户 ID 属性 1 用户 ID 属性 2 用户 ID 属性 3 用户 ID 属
  • 应用程序中 GC 长时间暂停

    我当前运行的应用程序需要最大堆大小为 16GB 目前我使用以下标志来处理垃圾收集 XX UseParNewGC XX UseConcMarkSweepGC XX CMSInitiatingOccupancyFraction 50 XX Di
  • Asp.net Mvc OutputCache属性和滑动过期

    Calling http foo home cachetest for UrlRoute Path home cachetest OutputCache Duration 10 VaryByParam none public ActionR
  • 基于Java模式分割字符串

    您好 我有以下模式的日志文件 2014 03 06 03 21 45 432 ERROR mfs pool 3 thread 19 dispatcher StatusNotification Error processing notific
  • mysql查询先慢后快

    我有 2 个 myISAM 表 分别称为 tests 和 completed tests 一个有 170 个条目 另一个有 118k 条目 当我运行此查询时 SELECT ct archive ct status ct score ct u
  • 如何在大空间尺度上加速A*算法?

    From http ccl northwestern edu netlogo models community Astardemo http ccl northwestern edu netlogo models community Ast
  • 预填充 UICollectionView 单元重用队列

    问题 我有一个应用程序 只有一个UICollectionView我第一次滚动它时很卡顿 我已将来源范围缩小到正在创建新单元格 2 的事实 使用initWithFrame 因为周围没有可以重复使用的细胞 初始滚动后 重用队列不为空 单元格可以
  • 读取大文件并制作字典

    我有一个大文件 我需要读取它并从中制作字典 我希望这一切能够尽可能快 然而我的Python代码太慢了 这是一个显示问题的最小示例 首先制作一些假数据 paste lt seq 20000000 lt seq 2 20000001 gt la
  • OCaml 前向声明

    有没有办法在 OCaml 中进行 C 风格的前向声明 我的问题是我有两个相互引用的变体 type path formula Next of state formula Until of state formula state formula
  • 如何加快 Java VM (JVM) 的启动时间?

    我正在运行启动多个 JVM 进程的测试 与 JVM 内运行的实际测试时间相比 JVM 的总结启动时间非常重要 我怎样才能加快速度 我已经使用了 client 选项 这确实有帮助 但没有我想要的那么多 还有其他方法吗 比如预加载一堆 JVM
  • 如何针对 IE 进行优化?

    我有一个 JS 密集型应用程序 它在 IE 中运行缓慢 我将花费大约一周的时间来优化 IE 并且我想要一些关于尝试的方向 我发现这个线程引用Drip https ieleak svn sourceforge net svnroot iele
  • 频繁插入已排序的集合

    我已经对集合 列表 进行了排序 并且我需要始终保持其排序 我目前在我的集合上使用 List BinarySearch 然后在正确的位置插入元素 我也尝试过在每次插入后对列表进行排序 但性能不可接受 有没有一种解决方案可以提供更好的性能 也许
  • 为什么在 data.frame 中预先指定类型会比较慢?

    我预先分配了一个大 data frame 以便稍后填写 我通常这样做NA是这样的 n lt 1e6 a lt data frame c1 1 n c2 NA c3 NA 我想知道如果我预先指定数据类型是否会让事情变得更快 所以我测试了 f1
  • 用 OpenCL C 编写快速线性系统求解器

    我正在编写一个 OpenCL 内核 它将涉及求解线性系统 目前我的内核太慢了 提高线性系统部分的性能似乎是一个不错的起点 我还应该注意 我并没有尝试使我的线性求解器并行 我正在研究的问题在宏观层面上已经是令人尴尬的并行 以下是我编写的 C

随机推荐