【问题标题】:How to reduce the execution time in Parallel.ForEach function?如何减少 Parallel.ForEach 函数的执行时间?
【发布时间】:2023-03-19 11:15:01
【问题描述】:

代码:

Parallel.ForEach(
    infoMap,
    map =>
    {
        var workItem = map.WorkItem;
        var parentInViews = viewMaps;
        var workbenchItem = map.WorkbenchItem;
        string LinkType = string.Empty;

        WorkItemLinkCollection linkedWorkItems = workItem.WorkItemLinkHistory;
        if (linkedWorkItems != null && linkedWorkItems.Count > 0)
            LinkType = linkedWorkItems[0].LinkTypeEnd.LinkType.ReferenceName;
        else if (workItem != null)
            LinkType = workItem.Store.WorkItemLinkTypes.LinkTypeEnds["Parent"].LinkType.ReferenceName;

        if (!string.IsNullOrEmpty(LinkType))
        {
            var viewMap = parentInViews.FirstOrDefault();
            if (viewMap != null)
            {
                var linkName =  LinkType;
                var childType = viewMap.ChildType;

                ILinkItem itm = Factory.BuildLinkItem(linkName, workbenchItem, workbenchItem);
                lock (Addparents)
                {
                    Addparents.Add(itm);
                }
            }
        }
    });

Factory.BuildLinkItem 定义:

public static ILinkItem BuildLinkItem(string linkName, IWorkbenchItem parent, IWorkbenchItem child)
{         
       return new LinkItem { LinkName = linkName ?? string.Empty, Child = child, Parent = parent };
}

全部存在658 items,执行上述Parallel.ForEach函数需要将近10秒

是否可以减少执行时间,如果可以,请建议我一个解决方案。谢谢。

注意:除了Parallel.ForEach,如果有任何替代方法可以提高性能并减少执行时间,请提出。谢谢。

【问题讨论】:

  • 您是否尝试过分析您的代码并查看花费的时间?
  • 因为我没有安装权限,所以我没有配置代码。
  • 你为什么要Addparents.Add(itm)?为什么不使用.ToList() 进行并行选择以将项目放入列表中?
  • @Enigmativity 我猜是因为编写这种代码比将多个 Select() 和 Where() 与所有这些状态结合起来要简单得多。
  • @Enigmativity,如何将Addparents.Add(itm); 更改为parallel select with a .ToList()。谢谢。

标签: c# .net performance parallel.foreach


【解决方案1】:

您的问题出在lock 语句中。与其他同步机制相比,其背后的mutex 机制在性能上极其昂贵。我敢打赌,这 10 秒中的 99.99%,代码都在那个关键部分锁定和等待。即使是非并行选择也会快得多。

您有两个选择。首先是使用.AsParallel() .Select().Where() 而不是Parallel.ForEach 并添加到锁内的集合中。我强烈推荐这个。这样,对不同项目的操作之间的同步就会自动处理。

第二个选项是使用 .NET 4 中存在的某种concurrent collection,而不是锁定和正常收集。这些集合经过特别优化,可以更快地添加项目,即线程安全。

这是小技巧,你怎么能简单地将其转换为AsParallel

infoMap.AsParallel().Select(
map =>
{
    var workItem = map.WorkItem;
    var parentInViews = viewMaps;
    var workbenchItem = map.WorkbenchItem;
    string LinkType = string.Empty;

    WorkItemLinkCollection linkedWorkItems = workItem.WorkItemLinkHistory;
    if (linkedWorkItems != null && linkedWorkItems.Count > 0)
        LinkType = linkedWorkItems[0].LinkTypeEnd.LinkType.ReferenceName;
    else if (workItem != null)
        LinkType = workItem.Store.WorkItemLinkTypes.LinkTypeEnds["Parent"].LinkType.ReferenceName;

    if (!string.IsNullOrEmpty(LinkType))
    {
        var viewMap = parentInViews.FirstOrDefault();
        if (viewMap != null)
        {
            var linkName =  LinkType;
            var childType = viewMap.ChildType;

            ILinkItem itm = Factory.BuildLinkItem(linkName, workbenchItem, workbenchItem);

            return new {item = itm, filter=true};
        }
    }
    return new {item = (ILinkItem)null, filter=false};
})
.Where(x=>x.filter)
.Select(x=>x.item)
.ToList();

【讨论】:

  • 您能否更新我的代码并相应地更改您的第一个选项First is to use .AsParallel() .Select() and .Where()。谢谢。
  • @Euphoric - 你怎么能不确定它是否有效。要么有效,要么无效。如果没有,那有什么不对劲的地方?什么错误?
  • @Euphoric,我尝试了.AsParallel() .Select() and .Where() 方法,效果很好。但是,与Parallel.ForEach 方法相比,在多次中,毫秒数略高。我使用System.Diagnostics.StopWatch 来测试两组代码的执行时间比较。最后,我将坚持使用Parallel.ForEach 方法,与.AsParallel() .Select() and .Where() 方法相比,在我测试的大多数情况下,它的执行时间更短。感谢您提出宝贵的建议和解决方案。
  • @JohnStephen 您的意思是与您的代码相比?你确定你测试正确吗?如果是这种情况,那么就有问题了,因为您的代码中没有任何内容表明 658 个项目需要 10 秒。我想到的其他事情是 Factory.BuildLinkItem 或者如果您使用实体框架,可能会延迟加载。
  • @Euphoric,是的,我与我的代码进行了比较,我确信我测试正确。此外,如果在这种情况下Factory.BuildLinkItem 可能是一个问题,我们是否可以有任何其他解决方法来代替使用Factory.BuildLinkItem。谢谢。以下是Factory.BuildLinkItem 定义。 public static ILinkItem BuildLinkItem(string linkName, IWorkbenchItem parent, IWorkbenchItem child) { return new LinkItem { LinkName = linkName ?? string.Empty, Child = child, Parent = parent }; }
猜你喜欢
  • 1970-01-01
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-03
  • 2012-12-31
  • 2016-01-29
相关资源
最近更新 更多