1

and loops でList<string>IEnumerable<string> 反復をテストしましたが、リストの方がはるかに高速である可能性はありますか?forforeach

これらは、私が見つけることができる数少ないリンクのうちの 2 つでありIEnumerableList.

リンク 1 リンク2

私のテストでは、URL のリストを保持するテキスト ファイルから 10,000 行をロードしていました。

最初に List にロードしてから、 List を IEnumerable にコピーしました

List<string> StrByLst = ...method to load records from the file .
IEnumerable StrsByIE =  StrByLst;

したがって、それぞれに10kアイテムがあります タイプ<string>

各コレクションを 100 回ループすると、つまり 100K の反復が発生します。

List<string> より驚くべき 50 倍高速ですIEnumerable<string>

それは予測可能ですか?

  • アップデート

これはテストを行っているコードです

string WorkDirtPath = HostingEnvironment.ApplicationPhysicalPath;
    string fileName = "tst.txt";
    string fileToLoad = Path.Combine(WorkDirtPath, fileName);
    List<string> ListfromStream = new List<string>();
    ListfromStream =  PopulateListStrwithAnyFile(fileToLoad) ;
    IEnumerable<string> IEnumFromStream = ListfromStream ;

    string trslt = "";
    Stopwatch SwFr = new Stopwatch();
    Stopwatch SwFe = new Stopwatch();

    string resultFrLst = "",resultFrIEnumrable, resultFe = "", Container = "";

    SwFr.Start();

    for (int itr = 0; itr < 100; itr++)
    {
        for (int i = 0; i < ListfromStream.Count(); i++)
        {
            Container = ListfromStream.ElementAt(i);
        }
    //the stop() was here , i was doing changes , so my mistake.
    }

   SwFr.Stop();
   resultFrLst = SwFr.Elapsed.ToString();
   //forgot to do this reset though still it is faster (x56??)
   SwFr.Reset();
   SwFr.Start();
        for(int itr = 0; itr<100; itr++)
        {
            for (int i = 0; i < IEnumFromStream.Count(); i++)
            {
                Container = IEnumFromStream.ElementAt(i);
            }
        }
    SwFr.Stop();
    resultFrIEnumrable = SwFr.Elapsed.ToString();

更新...最終

for ループの外にカウンタを取り出し、

int counter = ..countIEnumerable と List の両方

次に、 @ScottChamberlain によって提案された合計アイテム数として counter(int) を渡しました。すべてが整っていることを再確認した結果、IEnumerable が 5% 速くなりました。結論として、シナリオ別の使用 - ユースケース...パフォーマンスの違いはまったくありません...

4

3 に答える 3

4

あなたは何か間違ったことをしています。

基本的に同じコードを実行しているため、得られる時間は互いに非常に近いはずです。

IEnumerable は、List が実装する単なるインターフェイスであるため、IEnumerable 参照で何らかのメソッドを呼び出すと、List の対応するメソッドが呼び出されます。

IEnumerable に実装されたコードはありません。これがインターフェイスです。クラスが持つべき機能を指定するだけで、実装方法については何も述べていません。

于 2012-12-16T07:22:06.460 に答える
3

テストにはいくつかの問題があります.1つはループIEnumFromStream.Count()forです.その値を取得するたびに、リスト全体を列挙してカウントを取得する必要があり、値はループ間でキャッシュされません. その呼び出しをforループの外に移動し、結果を a に保存し、intその値をforループに使用すると、IEnumerable の時間が短くなります。

また、は必要なインデックスに直接ジャンプできるたびに、リスト全体を反復する必要があるのIEnumFromStream.ElementAt(i)と同様に動作します(例: 最初は、2 回目は、3 回目は...)。代わりに返された fromを使用する必要があります。Count()i00,10,1,2ListIEnumeratorGetEnumerator()

IEnumerableforループはうまく混ざりません。ジョブに適したツールを使用してください。それを呼び出して操作するか、ループGetEnumerator()で使用してください。foreach


さて、多くの人が「しかし、それは呼び出しをマッピングするだけのインターフェースであり、違いはないはずだ」と言っているかもしれませんが、重要なことがあります。 orメソッドIEnumerable<T> はありません! Count()ElementAt(). これらのメソッドは LINQ によって追加された拡張メソッドであり、LINQ クラスは基になるコレクションが List であることを認識しないため、基になるオブジェクトが実行できることを知っていることを実行し、メソッドが呼び出されるたびにリストを反復処理します。


IEnumerable使用してIEnumerator

using(var enu = IEnumFromStream.GetEnumerator())
{
    //You have to call "MoveNext()" once before getting "Current" the first time,
    //   this is done so you can have a nice clean while loop like this.
    while(enu.MoveNext())
    {
        Container = enu.Current;
    }
}

上記のコードは、基本的には

foreach(var enu in IEnumFromStream)
{
    Container = enu;
}

覚えておくべき重要なことはIEnumerable、 には長さがなく、実際には無限に長くなる可能性があるということです。無限の長さを検出するコンピューター サイエンスの全分野があります。IEnumerable

于 2012-12-16T07:55:13.703 に答える
1

Stopwatchあなたが投稿したコードに基づいて、問題はクラスの使用にあると思います。

これらのうちの 2 つと を宣言しSwFrますSwFeが、前者のみを使用します。このため、 への最後の呼び出しは、両方のループセットのSwFr.Elapsed合計時間を取得します。for

この方法でそのオブジェクトを再利用したい場合は、 のSwFr.Reset()直後に を呼び出しますresultFrLst = SwFr.Elapsed.ToString();

SwFeまたは、 2 番目のテストを実行するときに使用できます。

于 2012-12-16T07:36:48.590 に答える