0

そこで今朝、初めてベンチマークをいじってみることにしました。

「do-end」ブロック形式と「{ }」形式のコードの速度の違いに興味がありました。

そこで、ベンチマーク コードを Proc に格納して、複数回連続して呼び出すことができるようにしました。

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)

私には、これは私が期待しているものとは正反対のように見えます。分岐予測の概念に精通しています。これは分岐予測の典型的な例ですか? そうでない場合は、何ですか?このような不正確さを防ぐ方法はありますか (これが 1 つと見なされる場合でも)?

編集:いくつかの提案の後、このコードを30回以上実行しました。多くの場合、2 つの結果が交互に表示されます。データのサンプルは次の場所にあります。

gist.github.com/TheLarkInn/5599676

4

2 に答える 2

4

まず第一に、あなたのベンチマークはまったく無意味です。do/end構文と{/構文の違いは、}構文だけです。意味上の違いはありません。したがって、この 2 つの間にランタイム パフォーマンスの違いが生じることはあり得ません。それは論理的に不可能です。ベンチマークする必要はありません。

存在する可能性がある唯一のパフォーマンスの違いは、一方が他方よりも解析に時間がかかることです。ただし、どちらも他方より解析が難しくありません。唯一の違いは優先順位です。したがって、解析でもパフォーマンスの違いはほとんどありません。

また、解析にパフォーマンスの違いがあったとしても、ベンチマークには表示されません。Ruby で記述されたベンチマークを使用していますが、Ruby コードを実行するために、Ruby 実行エンジンはまずそれを解析する必要があります。つまり、ベンチマークが開始される前に解析が行われます。したがって、ベンチマークが無意味ではなかったとしても、解析のパフォーマンスの違いを測定できない可能性があるため、それでも役に立たないでしょう。

分岐予測に関する質問については、コードに分岐がなく、予測するものは何もありません。

ところで: ベンチマークが別の目的を意図していたとしても、少なくともより高度な Ruby 実装はブロックが本質的にノーオペレーションであることを認識し、単純にそれらを最適化して取り除くため、何も測定していません。また、それらが最適化されていないString場合でも、ブロックのパフォーマンスではなく、メモリ アロケーターのパフォーマンス (数百メガバイトの小さなオブジェクトの割り当て) だけが測定されます。

于 2013-05-17T14:36:17.363 に答える
1

統計に関する簡単な入門書:

トレンドを見つけるのに 2 回の実行で十分かどうかはわかりません。2 回目に実行したときに、2 つのテスト ブロックのシステム負荷に違いがあった場合はどうなるでしょうか。

2 つのサンプル間の統計的差異を判断するための経験則では、30 以上のデータ ポイントで統計的に関連性のある結果が得られます。

テストを少なくともその回数実行し、2 つのバージョンの結果を個別に保存してから、2 つのセットを相互に比較する前に、それらが一貫していることを確認するために内部で比較します。

あなたの最初の前提が間違っている可能性があります:)

于 2013-05-17T13:45:47.370 に答える