Parallels.ForEach与Foreach相同的时间

时间:2011-11-28 20:51:55

标签: c# .net 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);
        });
    }

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

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

FillDifferences方法调用一个静态类,该类使用反射来找出原始对象和修改对象之间存在多少差异。静态对象没有全局&#39;变量,只是被调用方法的本地变量。

有些人想看看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;
    }

2 个答案:

答案 0 :(得分:5)

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

  • 0ms == 1个帖子
  • 500ms == 2个帖子
  • 1000 ms == 3个帖子
  • 1500 ms == 4个帖子
  • 2000 ms == 5个帖子
  • 2500 ms == 6个帖子
  • 3000 ms == 7个帖子
  • 3500 ms == 8个帖子
  • 4000 ms == 9个帖子

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

System.Threading.ThreadPool.SetMaxThreads(4, 4);

答案 1 :(得分:0)

看看它在做什么,你的线程没有做任何事情的唯一时间是当操作系统将它们切换出来给另一个线程时,你可以获得能够在另一个核心上运行的好处 - 所有上下文切换的成本。

你必须抓住一些登录才能找到确定的,但我怀疑瓶颈是物理线程,除非你有一个你还没有发布的地方。

如果这是真的,我很想重新编写代码。有两个线程用于查找要比较的属性,一个用于比较它们和一个公共队列。可能是另一个在列表中抛出类并整理结果的人。

虽然可能是旧时批处理头。

相关问题