4

我想知道最好的方法是什么,或者是否有任何文档/文章可以帮助我确定在每个循环的正常范围内使用 Parallel.foreach 和 Task 的区别,如下所示:

案例 1 - Parallel.foreach:

Parallel.foreach
{
  // Do SOmething thread safe: parsing an xml and then save 
  // into a DB Server thry respoitory approach
}

案例 2 - foreach 中的任务:

foreach
{
  Task t1 = Task.factory.startNew(()=>
  {
     //Do the same thing as case 1 that is thread safe
  }
}
Task.waitall()
  • 我确实做了自己的测试,结果显示案例 1 的性能比案例 2 好。比率大约是这样的:顺序 vs 案例 1 vs 案例 2 = 5s : 1s : 4s

虽然案例 1 和案例 2 几乎是 1:4?那么这是否意味着如果我们想在循环中并行运行,我们应该始终使用 parallel.foreach 或 parallel.for?

4

3 回答 3

1

首先,关于该主题的最佳文档是 CLR 的第 V 部分。

http://www.amazon.com/CLR-via-C-Developer-Reference/dp/0735667454/ref=sr_1_1?ie=UTF8&qid=1376239791&sr=8-1&keywords=clr+via+c%23

其次,我希望 Parallel.Foreach 表现更好,因为它不仅会创建任务,还会对它们进行分组。在 Jeffrey Richter 的书中,他解释说,单独启动的任务将被放入线程池队列中。锁定实际线程池队列有一些开销。为了解决这个问题,任务本身有自己创建的任务队列。Tasks持有的这个任务子队列其实可以不加锁地做一些工作!

我将不得不再次阅读该章(第 27 章),所以我不确定 Parallel.Foreach 是否以这种方式工作,但这是我期望它做的。

他解释说,锁定很昂贵,因为它需要访问内核级结构。

在任何一种情况下,都不要期望它们按顺序处理。由于上述内部结构,使用 Parallel.Foreach 不太可能比 foreach 关键字进行顺序处理。

于 2013-08-11T16:56:00.860 回答
1

它的作用是Parallel.ForEach()创建少量Tasks 来处理循环的迭代。Tasks 相对便宜,但它们不是免费的,因此这往往会提高性能。而且你的循环体执行很快,改进可能非常大。这是您观察到的行为最可能的解释。

于 2013-08-11T12:25:59.817 回答
0

你正在运行多少个任务?如果循环足够多,仅创建一个新任务可能需要大量时间。即,第一个块的以下运行时间为 15 毫秒,第二个块的运行时间超过 1 秒,第二个块甚至不运行任务。取消注释Start,时间上升到近 3 秒。唯一的WaitAll增加了少量。

static class Program
{
    static void Main()
    {
        const int max = 3000000;
        var range = Enumerable.Range(0, max).ToArray();
        {
            var sw = new Stopwatch();
            sw.Start();
            Parallel.ForEach(range, i => { });
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
        {
            var tasks = new Task[max];
            var sw = new Stopwatch();
            sw.Start();
            foreach (var i in range)
            {
                tasks[i] = new Task(()=> { });
                //tasks[i].Start();
            }
            //Task.WaitAll(tasks);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}
于 2013-08-10T17:14:01.117 回答