我在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
所花的时间是
答案 0 :(得分:3)
您的foreach
版本会在个人资料操作中调用var localenumertaor = contactService.Download();
,而枚举器版本会在Profile
调用之外调用它。
最重要的是,迭代器版本的第一次执行将耗尽枚举器中的项目,并且在后续迭代itemsCollection.MoveNext()
将返回false并完全跳过内部循环。