为什么一个循环的性能优于其他内存以及性能?

时间:2012-07-01 05:22:20

标签: c# performance linq

我在C#中有两个循环,我正在为一个集合运行这些循环,其中有10,000条记录正在使用“yield return”进行分页下载

首先

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

第二

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

似乎第二个循环消耗的内存更少,并且比第一个循环更快。我理解的内存可能是因为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毫秒

1 个答案:

答案 0 :(得分:3)

您的foreach版本会在个人资料操作中调用var localenumertaor = contactService.Download();,而枚举器版本会在Profile调用之外调用它。

最重要的是,迭代器版本的第一次执行将耗尽枚举器中的项目,并且在后续迭代itemsCollection.MoveNext()将返回false并完全跳过内部循环。