LoginSignup
110
33

More than 3 years have passed since last update.

C#で配列に対してforとforeachどっちが速いの? ~実際試してみた~

Last updated at Posted at 2019-06-16

TL;DR

前回の続きと言う名の沼

少なくとも、.Net Coreの上で動かすのなら、forでもforeachでも好きな方使えばいいんじゃないかな?

検証に先立つ追記(教えて頂いた知見)

記事公開後にはぇ~☆先生から、ecxのコピーの件、

とのご指摘を頂いた。
確かにecxは32bit[^1]、r~~は64bitなのでこちらの方が理由としては大きいと考えた。

また、その後

と、教えて頂いた。

実際のCPUがどのようにAssemblyを解釈して実行してるのか全く知らなかったのでとても参考になりました。

教えて頂きありがとうございます。

ベンチマークはどのように実行されたのか

ベンチマークは概ね以下のプロセスで実行される。

詳細はHow it worksを参照してください。

  1. ベンチマークコードを独立したプロジェクトとして生成する
  2. イテレーションカウントの計測
  3. 関係ない部分のオーバーヘッドタイムの計測
  4. ウォーミングアップでベンチマークコードを実行
  5. 実計測(20個)

ウォーミングアップは、Managed heapのサイズを安定させるために行ってる。

また、実計測が20回では無く、20個なのは、明らかな外れ値を弾いて再実行しているため。

検証したデータ及び、呼称

以下の結果は、先に述べたとおり、様々な方から様々なCPUの実行結果の提供を受けた。
実データはgithubにまとまっている。

また、検証に使用した配列のサイズが900,000,000個は流石に多すぎると思い、サンプルは少ないが、配列のサイズが100,000個の場合もベンチマークを取っている。
この先、ArraySize=900,000,000を900M、ArraySize=100,000を100Kと表現する。

AMDの場合

AMD製のCPU/APUでこのベンチマークを実行した結果を以下に示す。

image.png

image.png

どちらの結果も、forを使ったループ操作を行った方が高速であることがわかる。

Intel

こっちはかなり複雑というか、割と凄いことになる。
まずは結果を示す。

image.png

image.png

グラフからわかるとおり、forが高速なパターンと、foreachが高速なパターンが存在する。
そこで、世代毎に並べた上で、どちらが高速なのかその比率を図示化してみた。

image.png

image.png

ratioの計算式は1-<速い方>/<遅い方>とし、forが速い場合は負値、foreachが速い場合は正値で表した結果となる。

ここから見えてくること

AMDとは異なり、画一的にどちらが速いと結論づけることが出来ない結果となっている。
具体的にはHaswellを境として、古いCPUはforが高速であり、それ以降のCPUはforeachが高速となっている。
また、全体的な傾向として、Haswell世代の比率が最も大きくなり、時代が下るに従ってその差は小さくなっており、2019年6月16日現在最新のCoffee Lakeではforeachが速いとは言え、その差は微少になっていることがわかる。

まとめ ~結論だけが残った~

おいらは、CPUのハードウェア的な知識が皆無なので、実験した結果をまとめるに留めておく。

  1. AMDのCPUは世代に関係なく常にforの方が高速。
  2. intelのCPUはHaswellを境として、それ以前のCPUならforが優位であり、それ以降ではforeachが優位である。
  3. 但し、その差は小さくなっている。

全体的にintel製のCPUが優勢な状況なので、どちらを使うべきかと言えば多分foreachの方だと考えられる。
しかしながら、その差は小さくなってきており、またAMD製のCPUではforの方が優位なので、TL;DRで述べたとおり、好きな方を使えば良いのではないかなと言う割と身も蓋もない結論となった。

補遺

コメントを頂いて、CPU以外の環境を明示していなかったので補遺としてリストしておきます。

cpu os sdk_version runtime
AMD Ryzen 7 1700X Windows 10.0.17763.529 (1809/October2018Update/Redstone5) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i7-3770K CPU 3.50GHz (Ivy Bridge) Windows 10.0.17763.557 (1809/October2018Update/Redstone5) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Pentium CPU 4415Y 1.60GHz Windows 10.0.17134.753 (1803/April2018Update/Redstone4) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i7-6700 CPU 3.40GHz (Skylake) Windows 10.0.17134.765 (1803/April2018Update/Redstone4) 3.0.100-preview5-011568 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i7-9700K CPU 3.60GHz (Coffee Lake) debian 9 2.2.300 .NET Core ? (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i7-8850H CPU 2.60GHz (Coffee Lake) macOS Mojave 10.14.5 (18F203) [Darwin 18.6.0] 3.0.100-preview5-011568 .NET Core 2.2.0 (CoreCLR 4.6.27110.04, CoreFX 4.6.27110.04), 64bit RyuJIT
Intel Core i5-3210M CPU 2.50GHz (Ivy Bridge) macOS Mojave 10.14.5 (18F132) [Darwin 18.6.0] 2.2.107 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i5-4200U CPU 1.60GHz (Haswell) Windows 10.0.17763.557 (1809/October2018Update/Redstone5) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i5-3337U CPU 1.80GHz (Ivy Bridge) Windows 10.0.17763.529 (1809/October2018Update/Redstone5) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
AMD Ryzen 5 PRO 2500U w/ Radeon Vega Mobile Gfx Windows 10.0.18362 3.0.100-preview5-011568 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i7-2620M CPU 2.70GHz (Sandy Bridge) macOS High Sierra 10.13.6 (17G7024) [Darwin 17.7.0] 2.2.107 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i5-7600 CPU 3.50GHz (Kaby Lake) Windows 10.0.17763.503 (1809/October2018Update/Redstone5) 3.0.100-preview-009812 .NET Core 2.2.3 (CoreCLR 4.6.27414.05, CoreFX 4.6.27414.05), 64bit RyuJIT
Intel Core i5-6267U CPU 2.90GHz (Skylake) macOS High Sierra 10.13.4 (17E199) [Darwin 17.5.0] 2.2.107 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
AMD A10-6800K APU with Radeon(tm) HD Graphics Windows 10.0.17763.348 (1809/October2018Update/Redstone5) 2.2.300 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
Intel Core i5-4300U CPU 1.90GHz (Haswell) Windows 10.0.17763.529 (1809/October2018Update/Redstone5) 3.0.100-preview4-011223 .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
110
33
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
110
33