ruby 性能 : Chaining selects vs AND-ing predicates?

标签 ruby performance

如果我想选择满足谓词p_1p_2 的数组arr 的所有元素,那么我有两个实现选项:

选项 1:

arr.select{|x| x.p_1}.select{|x| x.p_2}

选项 2:

arr.select{|x| x.p_1 && x.p_2}

两者之间有显着差异吗?在我的用例中,谓词 p_1p_2 减少了列表,而且 p_2p_1 更昂贵.所以我怀疑将 p_1 放在 p_2 之前会使它更快。但是,上述任何一个选项都会有所作为吗?

最佳答案

看来您已经了解谓词的性能特征和数据的形状,这太棒了!

有区别吗?简单地说,是的——评估顺序不同:

# Option 1
arr[0].p_1
arr[1].p_1
arr[2].p_1
...
arr[n].p_1
arr[0].p_2
arr[1].p_2
arr[2].p_2
...
arr[n].p_2

对比

# Option 2
arr[0].p_1
arr[0].p_2
arr[1].p_1
arr[1].p_2
arr[2].p_1
arr[2].p_2
...
arr[n].p_1
arr[n].p_2

现在,这重要吗?这取决于非常情况和上下文的副作用。作为示例,让我们探讨几个场景:

阻塞、缓冲 I/O

假设 p_2 成本高得多的原因是因为它执行一些 I/O,例如写入磁盘。可能是这种输出操作被缓冲的情况,虽然 Ruby 运行时可能从 p_2 调用返回,但到再次调用 p_2 时输出仍在刷新, 阻止它。

在这种特殊情况下,选项 2 更快,因为 p_1 计算可以在相互阻塞的 p_2 调用之间的过渡期间继续进行。

缓存未命中

假设 p_1 之所以快是因为它的计算可以被缓存。我们还假设调用 p_2 会以某种方式破坏缓存,从而导致后续 p_1 调用出现缓存未命中:

  • 也许它也添加到缓存中,并且缓存填满,逐出值
  • 也许缓存是按时间逐出的,缓存的数据在 p_1 调用之间被逐出,因为 p_2 花费的时间太长

在这种特殊情况下,选项 1 更快,因为分组的 p_1 调用能够利用缓存。

共享有限内存

假设 p_1p_2 调用都需要大量内存。也许通过交错使用它们,两者所需的资源必须始终随时可用,从而达到系统的内存限制,从而损害性能。

在这种情况下,选项 1 更快,因为一旦完成所有 p_1 调用,用于保存其资源的内存就可以释放出来供后面的 p_2 调用使用.

关于 ruby 性能 : Chaining selects vs AND-ing predicates?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52366705/

相关文章:

ruby-on-rails - 我什么时候/为什么要在方法上引发异常?

ruby - 退出注册机的正确方式是什么?

ruby - 正则表达式:如果字符串包含空格则不匹配

java - mmap() vs Java MappedByteBuffer 性能?

Mysql更新行以删除int辅助列间隙

java - 在 Java 方法性能中使用 final 关键字?

ruby - 打印 BFS 中的每个级别

c++ - 分析 C++ 多线程应用程序

performance - 如何调试数据库查询以提高性能

ruby - 如何使用 Ruby 的 ai4r gem 将神经网络保存到文件?