Parallels.ForEach与Foreach相同的时间

Aus*_*tin 10 .net c# parallel-processing task-parallel-library

所有,

我使用Parallels.ForEach如下

private void fillEventDifferencesParallels(IProducerConsumerCollection<IEvent> events, Dictionary<string, IEvent> originalEvents)
    {
        Parallel.ForEach<IEvent>(events, evt =>
        {
            IEvent originalEventInfo = originalEvents[evt.EventID];
            evt.FillDifferences(originalEventInfo);
        });
    }
Run Code Online (Sandbox Code Playgroud)

好的,所以我遇到的问题是我有28个这样的列表(一个测试样本,这应该可以扩展到200+)和FillDifferences方法非常耗时(每次调用大约4s).因此,在普通ForEach中运行的平均时间大约为100-130秒.当我在Parallel中运行相同的东西时,它需要相同的时间和Spikes我的CPU(Intel I5,2 Core,每个Core 2个线程)导致应用程序在此查询运行时变得迟缓(这是在一个线程上运行这是由GUI线程产生的).

所以我的问题是,我做错了什么导致这花费相同的时间?我读到List不是线程安全的所以我重写了这个以使用IProducerConsumerCollection.是否有任何其他陷阱可能导致这种情况?

FillDifferences方法调用一个静态类,该类使用反射来找出原始对象和修改对象之间存在多少差异.静态对象没有"全局"变量,只有被调用方法的局部变量.

有些人想看看FillDifferences()方法调用了什么.这是最终结束的地方:

  public  List<IDifferences> ShallowCompare(object orig, object changed, string currentName)
    {
        List<IDifferences> differences = new List<IDifferences>();
        foreach (MemberInfo m in orig.GetType().GetMembers())
        {
            List<IDifferences> temp = null;

            //Go through all MemberInfos until you find one that is a Property.
            if (m.MemberType == MemberTypes.Property)
            {
                PropertyInfo p = (PropertyInfo)m;
                string newCurrentName = "";
                if (currentName != null && currentName.Length > 0)
                {
                    newCurrentName = currentName + ".";
                }
                newCurrentName += p.Name;
                object propertyOrig = null;
                object propertyChanged = null;

                //Find the property Information from the orig object
                if (orig != null)
                {
                    propertyOrig = p.GetValue(orig, null);
                }

                //Find the property Information from the changed object
                if (changed != null)
                {
                    propertyChanged = p.GetValue(changed, null);
                }

                //Send the property to find the differences, if any. This is a SHALLOW compare.
                temp = objectComparator(p, propertyOrig, propertyChanged, true, newCurrentName);
            }
            if (temp != null && temp.Count > 0)
            {
                foreach (IDifferences difference in temp)
                {
                    addDifferenceToList(differences, difference);
                }
            }
        }
        return differences;
    }
Run Code Online (Sandbox Code Playgroud)

Cha*_*ion 5

我相信你可能会遇到线程上下文切换的代价.由于这些任务是长期运行的,我可以想象在ThreadPool上创建了许多线程来处理它们.

  • 0ms == 1个线程
  • 500ms == 2个主题
  • 1000毫秒== 3个主题
  • 1500毫秒== 4个线程
  • 2000毫秒== 5个主题
  • 2500毫秒== 6个线程
  • 3000毫秒== 7个主题
  • 3500毫秒== 8个线程
  • 4000毫秒== 9个主题

到4000ms只完成了第一项任务,因此这个过程将继续进行.可能的解决方案如下.

System.Threading.ThreadPool.SetMaxThreads(4, 4);
Run Code Online (Sandbox Code Playgroud)

  • @Austin:好的,但不要使用SetmaxThreads.向ForEach添加ParallelOptions. (3认同)