|
|
連載:[完全版]究極のC#プログラミング
Chapter3 新しい繰り返しのスタイル ― yield return文とForEachメソッド
川俣 晶
2009/08/31 |
 |
|
3.12 性能比較
さて、ここで気になるのは反復子とForEachメソッドのどちらを使うべきかである。ソースコードの簡潔さは大差ないとすれば、残ったポイントは性能といえる。
そこで、反復子とForEachメソッドの速度比較を行ってみた。リスト3.14はそのために作成したテストプログラムである。
using System;
using System.Collections.Generic;
class Program
{
private static IEnumerable<int> getCounter(int from, int to)
{
for (int i = from; i <= to; i++) yield return i;
}
private static void forEach(int from, int to, Action<int> action)
{
for (int i = from; i <= to; i++) action(i);
}
static void Main(string[] args)
{
const int TestCount = 1000000000;
DateTime start1 = DateTime.Now;
int sum1 = 0;
foreach (int i in getCounter(1, TestCount))
{
sum1 += i;
}
Console.WriteLine(DateTime.Now - start1);
DateTime start2 = DateTime.Now;
int sum2 = 0;
forEach(1, TestCount, delegate(int i)
{
sum2 += i;
});
Console.WriteLine(DateTime.Now - start2);
Console.WriteLine(sum1 == sum2);
}
}
|
|
リスト3.14 反復子とForEachメソッドの速度比較 |
00:00:20.5880586
00:00:07.5447544
True
|
|
リスト3.14の実行結果(Visual Studio 2008のリリースビルド) |
実行結果は、1行目が反復子による実行時間、2行目はForEachメソッドによる実行時間、3行目は2つの処理結果の累積値が同じ(つまり、同じ回数を繰り返した証拠)ということを示すTrueが出力されている。
これを見ると一目瞭然だが、ForEachメソッドを使ったほうが圧倒的に速い。デバッグビルドにすると差は縮まるが、やはりForEachメソッドのほうが速い。
なぜForEachメソッドのほうが速いのかは、内部構造を考えれば容易にわかるだろう。ForEachメソッドは、繰り返し1回ごとにメソッドを1回だけ呼ぶ。しかし、反復子はMoveNextメソッドを呼んでからCurrentプロパティで値を取得する必要があり、2回の呼び出しが発生する。さらに、周辺にかなり込み入ったコードが生成されていることから考えて、大きな性能差が出るのはやむをえないところだろう。
さて、ここでの結論は列挙よりもForEachメソッドを使うほうが優れている……ということでよいのだろうか? 自作のオブジェクトに列挙インターフェースを付けることは意味がなく、ForEachメソッドさえ付けておけばよいのだろうか?
そうではない。実は、C# 3.0のキーとなる重要技術の1つであるLINQ(第15章〜第18章参照)は「列挙できるものはクエリできる」という機能を発揮する。単に高速に列挙するだけならForEachメソッドでもよいのだが、LINQのクエリ式の中でオブジェクトを活用したいと思うなら、列挙インターフェースを追加することは重要な意味を持つ。そして、それをyield return文で簡潔に記述するノウハウにも重要な意味がある。
【Exercise】練習問題
foreach文とForEachメソッドについて誤った説明を選べ。
- 1 実行速度に差がある
- foreachは文であるがForEachはメソッドなので、使いたい対象を列挙するForEachメソッドを作成しないと使えない
- foreach文そのものは言語の一部なので自作することは難しいが、ForEachメソッドは簡単に自作できる
- yield return文で列挙できる
- 名前が違う
◎解答:「 4 」(この行をマウスで選択してください)
Insider.NET 記事ランキング
本日
月間