- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当你只有一把锤子时,一切看起来都像钉子。因此,在发现 Array#map
和 Array#select< 的实用性、优雅性和语法乐趣之前,可以说是 Ruby 中的
和其他可迭代方法。我很好奇的是:Array#each
方法
为什么在使用更精确的可迭代方法时性能会实际提高?一般来说,这是真的吗?
例如,在
require 'benchmark'
array = (1..100000).to_a
puts Benchmark.measure {
100.times do
array.map { |el| el.even? }
end
}
puts Benchmark.measure {
100.times do
new_array = []
array.each do |el|
new_array << el.even?
end
end
}
# ruby bench.rb
# 0.450598 0.015524 0.466122 ( 0.466802)
# 0.496796 0.018525 0.515321 ( 0.516196)
Benchmark
始终显示有利于 Array#map
的时间性能差异。在以下代码中:
puts Benchmark.measure {
100.times do
array.select { |el| el.even? }
end
}
puts Benchmark.measure {
100.times do
new_array = []
array.each do |el|
if el.even?
new_array << el
end
end
end
}
# ruby bench.rb
# 0.405254 0.007965 0.413219 ( 0.413733)
# 0.471416 0.008875 0.480291 ( 0.481079)
Array#select
每次都击败了一个偷工减料的 Array#each
。
那么为什么这些更精确的方法会产生明显更好的性能呢?这是 Ruby 和/或所有语言中的通用公理吗?
最佳答案
在您的两个示例中,第二段代码分配的内存是第一段代码的 100 倍。它还对数组执行大约 log_1.5(100) 次调整大小(假设动态数组的标准教科书实现具有 1.5 的增长因子)。调整数组的大小是昂贵的(分配一个新的内存块,然后将所有元素的 O(n) 副本复制到新的内存块中)。更一般地说,垃圾收集器讨厌突变,它们收集大量生命周期短的小对象比保持一些生命周期长的大对象更有效。
换句话说,在第一个示例中,您正在测量 Array#map
和 Array#select
,分别,而在第二个例子中,你不仅测量 Array#each
, 还有 Array#<<
以及数组大小调整和内存分配。从基准测试结果中无法判断哪些贡献了多少。正如 Zed Shaw 曾经说过的那样:"If you want to measure something, then don't measure other shit" .
但即使您在基准测试中修复了该错误,一般来说,更专业的操作比通用操作具有更多可用信息,因此更通用的操作通常不会比专业操作更快。
在您的特定示例中,它可能只是一些非常简单的事情,例如,您使用的 Ruby 实现不太擅长优化 Ruby 代码(例如 YARV,与 TruffleRuby 不同),同时具有优化的Array#map
的 native 实现和 Array#select
(再次以 YARV 为例,它对这两者都有 C 实现,并且通常不能很好地优化 Ruby 代码)。
最后,编写正确的微基准测试很困难。真的,真的,真的很难。我鼓励阅读并理解 mechanical-sympathy 上的整个讨论主题。邮寄名单:JMH vs Caliper: reference thread .虽然它专门针对 Java 基准测试(实际上是关于 JVM 基准测试),但许多论点适用于任何现代高性能 OO 执行引擎,例如 Rubinius、TruffleRuby 等。在较小程度上也适用于 YARV。请注意,大部分讨论都是关于编写微基准测试工具,而不是编写微基准测试本身,即它是关于编写允许开发人员编写正确的微基准测试的框架,不必了解那些东西,但不幸的是,即使有最好的微基准测试工具(Ruby 的 Benchmark
实际上不是一个很好的工具),您仍然需要对现代编译器、垃圾收集器、执行引擎、CPU、硬件架构有非常深刻的理解, 还有统计数据。
这是一个失败的基准测试的好例子,对于未受过训练的基准测试编写者来说可能并不明显:Why is printing “B” dramatically slower than printing “#”? .
关于ruby - 为什么#map 比#each 更有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60011859/
我有一个功能是转换 ADO Recordset 进入html: class function RecordsetToHtml(const rs: _Recordset): WideString; 该函
经过几天的研究和讨论,我想出了这种方法来收集访客的熵(你可以看到我的研究历史here) 当用户访问时,我运行此代码: $entropy=sha1(microtime().$pepper.$_SERVE
给定一个无序列表 List ,我需要查找是否存在 String与提供的字符串匹配。 所以,我循环 for (String k : keys) { if (Utils.keysM
我已经搜索过这个问题,但没有找到我正在寻找的答案。 基本上,我想将类构造函数包装在 try/except 子句中,以便它忽略构造函数内特定类型的错误(但无论如何都会记录并打印它们)。我发现做到这一点的
我有一组三个数字,我想将一组数字与另一组数字进行比较。即,第一组中的每个数字小于另一组中的至少一个数字。需要注意的是,第一组中的下一个数字必须小于第二组中的不同数字(即,{6,1,6} 对 {8,8,
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 9 年前。 Improve this
首先介绍一下背景: 我正在开发一个带有 EJB 模块和应用程序客户端模块的企业应用程序 (ear)。我还使用 hibernate JPA 来实现持久性,并使用 swingx 来实现 GUI。这些是唯一
我正在尝试在我的上网本上运行 Eclipse 以便能够为 Android 进行开发。 您可能已经猜到了,Eclipse 非常慢,并且不容易有效地开发。 我正在使用 Linux Ubuntu 并且我还有
for row, instrument in enumerate(instruments): for col, value in enumerate(instrument):
return not a and not b ^ 我如何以更好的格式表达它 最佳答案 DeMorgan's Law , 也许? return not (a or b) 我认为在这一点上已经足够简单了
我正在尝试让 Font Awesome 图标看起来更 slim https://jsfiddle.net/cliffeee/7L6ehw9r/1/ . 我尝试使用“-webkit-text-strok
假设我有一个名为 vals 的数据框,如下所示: id…………日期…………min_date…… .........最大日期 1…………2016/01/01…………2017/01/01…………2018/
是否有更 Pythonic 的方式来做到这一点?: if self.name2info[name]['prereqs'] is None: se
我有一个函数可以将一些文本打印到它接收到的 ostream&。如果 ostream 以终端为目标,我想让它适应终端宽度,否则默认为某个值。 我现在做的是: 从 ostream 中获取一个 ofstre
这个问题在这里已经有了答案: Should a retrieval method return 'null' or throw an exception when it can't produce
我有这个 bc = 'off' if c.page == 'blog': bc = 'on' print(bc) 有没有更 Pythonic(和/或更短)的方式在 Python 中编写? 最佳
输入:一个包含 50,000 行的 CSV;每行包含 910 列值 0/1。 输出:运行我的 CNN 的数据框。 我编写了一个逐行读取 CSV 的代码。对于每一行,我将数据分成两部分,称为神经元(90
据我所知,with block 会在您退出 block 后自动调用 close(),并且它通常用于确保不会忘记关闭一个文件。 好像没有技术上的区别 with open(file, 'r+') as f
我有一个使用 Entity Framework V6.1.1 的 MVC 5 网站。 Entity Framework DbContext 类和模型最初都在网站项目中。这个项目有 3 个 DbCont
我是编程新手,在尝试通过将 tableView 和关联 View 的创建移动到单独的类并将委托(delegate)和数据源从 VC 移动到单独的类来精简我的 ViewController 时遇到了一些
我是一名优秀的程序员,十分优秀!