【问题标题】:How to increase performance of foreach loop? [closed]如何提高 foreach 循环的性能? [关闭]
【发布时间】:2018-02-24 08:01:22
【问题描述】:

如何提高性能(大约需要 10 秒)这个 foreach 循环

foreach (var item in pList)
{
    var foundedItem = source.FirstOrDefault(x => x.LongRecordId == item.LongRecordId);
    if (foundedItem != null && !selectionList.Contains(foundedItem))
    {
        foundedItem.Readonly = pReadonly;
        selectionList.Add(foundedItem);
    }
}

【问题讨论】:

  • 提高性能并非易事。但也许您可以尝试为您的item 使用实际类而不是var
  • 使用 for 循环代替。
  • 问题可能出在您的selectionList.Contains(foundedItem) 上。我不知道您的项目有多复杂,以及您在该列表中存储了多少项目。但你可能想试试Dictionary
  • 瓶颈可能是source 上的LINQ。与source 相比,pList 中的项目数的典型关系是什么?将任一预计算到字典中可以是一种方法。进行一些分析以真正找出答案(假设您的意思是包括循环体代码在内的性能,而不仅仅是 pList 迭代器的性能,您没有显示)
  • 正是我所说的。

标签: c# winforms foreach


【解决方案1】:

如果sourcepList 很长,您可以尝试将source 转换为Dictionary

 // Provinding that all LongRecordId are distinct
 var dict = source
    .ToDictionary(item => item.LongRecordId, item => item);

 ...

 foreach (var item in pList) {
   MyRecord foundItem = null; //TODO: Put the right type here

   // Instead of O(N) - FirstOrDefault we have O(1) TryGetValue
   if (dict.TryGetValue(item.LongRecordId, out foundItem)) {
     foundItem.Readonly = pReadonly;
     selectionList.Add(foundItem);
   } 
 }

编辑:如果您想确保 selectionList 仅包含 不同 项(请参阅 Ferhat Sayan 的评论),请尝试 HashSet

 ...

 HashSet<MyRecord> selectedHash = new HashSet<MyRecord>(selectionList);

 foreach (var item in pList) {
   MyRecord foundItem null; //TODO: Put the right type here

   // Instead of O(N) - FirstOrDefault we have O(1) TryGetValue
   if (dict.TryGetValue(item.LongRecordId, out foundItem)) {
     foundItem.Readonly = pReadonly;
     selectedHash.Add(foundItem);
   } 
 }

 selectionList = selectedHash.ToList();

【讨论】:

  • 这个例子没有检查该项目是否已经在 selectionList 中,这也可能是一个瓶颈。但是,是的,它应该指向正确的方向。
  • @Ferhat Sayan:如果我们想确保selectionList 只包含不同的项目,我们可以尝试HashSet&lt;T&gt;
  • 非常感谢它提高了性能。旧版本列表打开 10 秒现在 1 秒这对我很有帮助
【解决方案2】:

我建议分析那段代码。

我猜最耗时的调用是 FirstOrDefault-Extension 方法。

如果有任何性能提升,使用 for 代替 foreach 不太可能给您带来太多好处。

很可能您的问题源于您的上下文变量,也许是一个非常大的源列表?

总体而言,此代码部分可能不是寻找性能改进的最佳位置。如果这是唯一的地方,您应该考虑重新设计。

如果您有非常大的列表并且不担心并发问题,您可以采用并行或多处理路线。 parallel.foreach 是一种进行一些测试的廉价方法。

使用字典而不是列表应该可以加快速度。如果您使用 HashSet(以产生 uniqunes 的好处),请注意实现适当的 IEqualityComparer,或者当您添加大量依赖 DefaultComparer 的项目时,您甚至可以lose performance

【讨论】:

  • FirstOrDefaultIMO无关。
  • 我不这么认为。如果您使用此处所示的列表设置模拟代码并对其进行分析,您会发现 FirstOrDefault 是最耗时的调用之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2021-06-19
  • 1970-01-01
  • 2020-08-25
  • 2021-07-04
  • 2019-10-29
  • 2013-08-14
相关资源
最近更新 更多