2

我在 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问题本身的基准测试小代码

花费的时间是

  • 对于每个经过的分析时间 5249 毫秒
  • 分析时间经过 116 毫秒
4

1 回答 1

3

您的foreach版本var localenumertaor = contactService.Download();在配置文件操作内部调用,而枚举器版本在调用外部调用它Profile

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

于 2012-07-01T15:13:55.880 回答