所以今天早上我决定第一次使用基准测试。
我很好奇使用"do-end"块格式的代码与使用"do-end"块格式的代码之间的速度差异。"{}"格式化。
因此,我将基准代码存储在一个进程中,以便我可以连续多次调用它:n = 100_000_000
bmp = Proc.new do
Benchmark.bm do |x|
x.report {n.times {a = "1"}}
x.report {n.times do; a = "1"; end}
end
end
我的结果是预期的,当我运行一次。
>> bmp.call
user system total real
1.840000 0.030000 1.870000 ( 1.874507)
1.860000 0.050000 1.910000 ( 1.926101)
=> true
然后再运行一遍。
>> bmp.call
user system total real
1.870000 0.050000 1.920000 ( 1.922810)
1.840000 0.000000 1.840000 ( 1.850615)
对我来说,这看起来与我所期望的完全相反。我熟悉分支预测的概念。这是分支预测的经典例子吗?如果不是,那是什么?有没有办法防止这样的不准确(如果这被认为是一种)?
编辑:在一些建议之后,我确实运行了这段代码超过30次。它经常在两种结果之间交替。数据示例如下:gist.github.com/TheLarkInn/5599676
首先,您的基准测试完全没有意义。do
/end
语法与{
/}
语法的区别只是:语法。没有语义上的区别。因此,不可能在两者之间有任何运行时性能差异。这在逻辑上是不可能的。你不需要对它进行基准测试。
可能存在的唯一性能差异是,一个比另一个需要更长的解析时间。然而,两者中没有一个比另一个更难解析。唯一的区别是优先级。因此,很可能在解析中也没有任何性能差异。
即使在解析中存在的性能差异,您的基准测试也不会显示它。您正在使用用Ruby编写的基准测试,但是为了运行Ruby代码,Ruby执行引擎必须首先解析它,这意味着在基准测试开始之前,解析就已经发生了。因此,即使您的基准测试不是无意义的,它仍然是无用的,因为它不可能测量解析中的性能差异。关于你关于分支预测的问题:你的代码中没有分支,没有什么可以预测的。
顺便说一句:即使你的基准测试是为了不同的目的,它仍然不会测量任何东西,因为至少更高级的Ruby实现会认识到你的块本质上是无操作的,并简单地优化它们。即使它们没有优化,它们所测量的只是内存分配器的性能(分配几百兆字节的微小String
对象),而不是块的性能。
简单介绍一下统计数据:
我不确定两次运行是否足以发现趋势。如果在第二次运行测试块时,两个测试块之间的系统负载存在差异,该怎么办?
确定两个样本之间的统计差异的经验法则是,30个或更多的数据点将为您提供统计相关的结果。
我会至少运行那么多次测试,独立存储两个版本的结果,然后在内部比较它们以确保它们是一致的,然后再将两个集合相互比较。
这可能是你的初始前提是不正确的:)