2

私はC#で次の2つのループを持っています.10,000レコードのコレクションに対してこれらのループを実行しています.「yield return」を使用したページングでダウンロードされています.

初め

foreach(var k in collection) {
  repo.Save(k);
}

2番

 var collectionEnum = collection.GetEnumerator();
 while (collectionEnum.MoveNext()) {
   var k = collectionEnum.Current;
   repo.Save(k);
   k = null;
 }

2 番目のループはメモリの消費量が少なく、最初のループよりも高速のようです。私が理解しているメモリは、(よくわかりませんが)kに設定されていることが原因である可能性がありnullます。しかし、なぜそれは よりも速いのですかfor each

以下は実際のコードです

  [Test]
    public void BechmarkForEach_Test() {
        bool isFirstTimeSync = true;
        Func<Contact, bool> afterProcessing = contactItem => {
            return true;
        };

        var contactService = CreateSerivce("/administrator/components/com_civicrm");
        var contactRepo = new ContactRepository(new Mock<ILogger>().Object);
        contactRepo.Drop();
        contactRepo = new ContactRepository(new Mock<ILogger>().Object);

        Profile("For Each Profiling",1,()=>{
            var localenumertaor=contactService.Download();
            foreach (var item in localenumertaor) {

            if (isFirstTimeSync)
                item.StateFlag = 1;

            item.ClientTimeStamp = DateTime.UtcNow;

            if (item.StateFlag == 1)
                contactRepo.Insert(item);
            else
                contactRepo.Update(item);

            afterProcessing(item);


        }
        contactRepo.DeleteAll();
        });

    }


    [Test]
    public void BechmarkWhile_Test() {
        bool isFirstTimeSync = true;
        Func<Contact, bool> afterProcessing = contactItem => {
                                                                 return true;
        };

        var contactService = CreateSerivce("/administrator/components/com_civicrm");
        var contactRepo = new ContactRepository(new Mock<ILogger>().Object);
        contactRepo.Drop();
        contactRepo = new ContactRepository(new Mock<ILogger>().Object);

        var itemsCollection = contactService.Download().GetEnumerator();

        Profile("While Profiling", 1, () =>
            {
                while (itemsCollection.MoveNext()) {

                    var item = itemsCollection.Current;
                    //if First time sync then ignore and overwrite the stateflag
                    if (isFirstTimeSync)
                        item.StateFlag = 1;

                    item.ClientTimeStamp = DateTime.UtcNow;

                    if (item.StateFlag == 1)
                        contactRepo.Insert(item);
                    else
                        contactRepo.Update(item);

                    afterProcessing(item);

                    item = null;
                }
                contactRepo.DeleteAll();

            });
    }

    static void Profile(string description, int iterations, Action func) {

        // clean up
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        // warm up 
        func();

        var watch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    }

私はマイクロ ベンチ マーキングを使用しています。stackoverflow の質問自体から、benchmarking-small-code

かかった時間は

  • プロファイリングごとの経過時間 5249 ミリ秒
  • プロファイリング時間の経過中 116 ms
4

1 に答える 1

3

バージョンはプロファイル アクション内でforeach呼び出しますが、列挙子バージョンは呼び出しの外で呼び出します。var localenumertaor = contactService.Download();Profile

その上、反復子バージョンの最初の実行で列挙子の項目が使い果たされ、その後の反復でitemsCollection.MoveNext()false が返され、内側のループが完全にスキップされます。

于 2012-07-01T15:13:55.880 に答える