【问题标题】:What are the main differences between using Parallel.ForEach & Task.Factory.StartNew使用 Parallel.ForEach 和 Task.Factory.StartNew 的主要区别是什么
【发布时间】:2016-10-31 11:56:18
【问题描述】:

我正在开发一个 asp.net mvc-4 Web 应用程序。但我不确定使用这两种方法对列表进行迭代和启动 WebClient() 调用之间有什么区别:-

方法一

Parallel.ForEach(photos,new ParallelOptions { MaxDegreeOfParallelism = 7 }, p =>
                            {
         ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
         WebClient wc = new WebClient();               

         var json =  wc.DownloadString(p.url);
         resourceAccountListInfo = JsonConvert.DeserializeObject<ResourceAccountListInfo>(json);
         if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
                    {
                        List<CUSTOMFIELD> customfield = resourceAccountListInfo.operation.Details.CUSTOMFIELD.Where(a =>
                                 a.CUSTOMFIELDLABEL.ToLower() == "name"
                                ).ToList();
                        if (customfield.Count == 1)
                        {
                            PMresourcesOnly.Add(resourceAccountListInfo.operation.Details);

                        }

                    }
            //code goes here
                            });

方法 2

   foreach (Photo p in photos)
                        {
            Task.Factory.StartNew(() =>
                        {
            ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
            WebClient wc = new WebClient();

            var json =  wc.DownloadString(p.url);
            resourceAccountListInfo = JsonConvert.DeserializeObject<ResourceAccountListInfo>(json);
                     if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
                    {
                        List<CUSTOMFIELD> customfield = resourceAccountListInfo.operation.Details.CUSTOMFIELD.Where(a =>
                                 a.CUSTOMFIELDLABEL.ToLower() == "name"
                                ).ToList();
                        if (customfield.Count == 1)
                        {
                            PMresourcesOnly.Add(resourceAccountListInfo.operation.Details);

                        }

                    }
            //code goes here
                                });
                        }

谢谢

【问题讨论】:

  • 所有线程都替换resourceAccountListInfo吗?这似乎是错误的
  • 不同之处在于: Parallel.ForEach 等到所有“照片”完成,然后继续。在 Task.Factory.StartNew 中,无论照片是否完成,它始终会继续。
  • @ScottChamberlain 抱歉,我只显示了与我的问题相关的部分代码。现在每次迭代中的 resourceAccountListInfo 都有额外的处理......
  • 最终,您可以根据自己的需要为您的代码选择最佳解决方案;我想总是很难确定什么是最合适的,所以你需要根据不同的解决方案如何工作来定义它,所以它需要一些试验和错误,以及性能指标,并且必须检查哪个是最合适的我认为最好的 :) 我只是想给我的两分钱!
  • @johnG 有很多方法可以让代码做同样的事情,我不认为你可以概括地说 Parallel.ForEach 比 Task.WhenAll 差,反之亦然 except 在某些情况下......即使在那些情况下,它们可能无论如何都会有相同的最终结果,所以这并不重要。在性能方面可能很重要。您应该在运行时在任务管理器中查看您的 CPU 核心使用情况,看看您是否正在使用所有 CPU 可计算性。

标签: c# asp.net .net asp.net-mvc parallel-processing


【解决方案1】:

Parallel.ForEach 为遍历集合提供了便利。 尽管Task.Factory.StartNew 可以在循环中调用,但它本身并没有表明它将在循环中使用。您可能只开始一项任务。

因为Parallel.ForEach 假定一组 并行操作,它为您提供ParallelOptions,允许您指定该循环范围内的并发操作数。这很有用,因为在某些情况下我们可能不关心有多少并发操作,但在其他情况下我们可能会关心。看看this answer,它描述了使用Semaphore 来限制并发任务的数量。设置MaxDegreeOfParallelism 比使用Semaphore 容易得多。

另外,Parallel.ForEach 返回一个ParallelLoopResult,它使您可以看到循环中的所有操作。要想在一组任务中获得同样的可见性,还需要做更多的工作。您还可以通过一个方法调用来停止循环,而不是停止多个任务。

【讨论】:

  • 所以你使用 Parallel.ForEach 而不是使用 Tas.Factory.StartNew 这是正确的吗?第二个问题在我的情况下使用 Parallel.Foreach 时,我是否需要明确使用 lock 以确保没有任何数据损坏或者这不是必需的?
  • 如果我正在处理一个我想并行处理的集合,我会使用Parallel.ForEach。否则我可能会启动Task。如果并行任务在需要它的东西上运行,例如它们不能同时更新的共享属性,您将需要使用某种锁定(或其他管理并发的方式)。但是这种锁定更有可能出现在我正在使用的对象中——编写它们以便它们支持并发——而不是在循环本身中。
  • “否则我可能会开始一个任务”到底是什么意思?当我需要对 Parallel.forEach 或 Tasks 使用 lock 时?你能提供更多细节吗?
  • 这有点深入。我将从阅读何时使用锁开始。它适用于任何多线程。
  • 所以即使我选择使用 Tasks.whenAll 也需要使用锁吗?
猜你喜欢
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 2012-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多