C#におけるforeach文とfor文による添え字アクセスのパフォーマンス検証
C#においてforeach文とfor文で添え字アクセスする方法のどちらを用いたほうがパフォーマンスが上がるのかについて気になっていました。
普段良く使う配列(Arrayクラス)とListクラスについて、foreach文とfor文によるシーケンシャルアクセスの速度を検証してみました。
今回用いたプログラムは以下の通りです。
class Program { static void Main(string[] args) { const int ELEM_NUM = 1000000; object[] objArray = new object[ELEM_NUM]; for (int i = 0; i < ELEM_NUM; ++i) { objArray[i] = new object(); } System.Console.WriteLine("Array"); Test(objArray); List<object> objList = new List<object>(); for (int i = 0; i < ELEM_NUM; ++i) { objList.Add(new object()); } System.Console.WriteLine(""); System.Console.WriteLine("List"); Test(objList); System.Console.ReadLine(); } public static void Test<t>(IList<t> objList) { const int LOOP_NUM = 100; System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); object obj; // foreach sw.Restart(); for (int i = 0; i < LOOP_NUM; ++i) { foreach (var elem in objList) { obj = elem; } } sw.Stop(); System.Console.WriteLine("foreach time = " + sw.Elapsed); // index sw.Restart(); for (int i = 0; i < LOOP_NUM; ++i) { for (int j = 0; j < objList.Count; ++j) { obj = objList[j]; } } sw.Stop(); System.Console.WriteLine("index time = " + sw.Elapsed); } }
実行結果は以下のようになりました。
■Debug版
Array foreach time = 00:00:00.9181903 index time = 00:00:01.3635538 List foreach time = 00:00:01.5507959 index time = 00:00:01.4055962
■Release版
Array foreach time = 00:00:00.6986892 index time = 00:00:01.1227786 List foreach time = 00:00:01.3271968 index time = 00:00:00.9576023
上記より、配列ではforeach文を用いたほうが速いようです。
Listクラスではfor文による添え字アクセスのほうが速いようです。
線形リストへの要素アクセスは通常でo(n)の処理コストがかかるため、ちょっと意外でした。
恐らく、シーケンシャルアクセスの場合は内部的に直近の要素への参照を保持しているなどで対策を施しているのかもしれません。
foreach文の場合はcollection.MoveNext()メソッドを呼び出してからcollection.Currentを呼び出す必要があるため、このワンクッションで時間がかかっている・・・のかもしれません。
foreachとfor文による添え字アクセスはどちらもそれほどパフォーマンスが劇的に低下することは無いので、状況に応じて使いやすいほうを使うので問題ないと思います。