1

我写了两个简单的循环。

一种是使用标准“for”:

Stopwatch sw = Stopwatch.StartNew(); 

            for (int i = 0; i < 1000000; i++)
            {
                Console.WriteLine(i);
            }
            sw.Stop();
            Console.WriteLine(sw.Elapsed);
            Console.ReadKey();

其次是使用 Parrallel.For,它应该更快:

sw.Restart();
            Parallel.For(0,1000000,i =>
                    {
                        Console.WriteLine(i);
                    });              

            sw.Stop();
            Console.WriteLine(sw.Elapsed);

不幸的是,第一个执行大约需要 53 秒,第二个执行大约需要 1 分 50 秒(!!!)。

为什么会这样,我做错了什么?

4

3 回答 3

4

Parallel.For不应该使循环更快。它应该使其迭代并行执行。

在您的尝试中,您使用的代码所使用的资源无法与并行化循环所提供的任何速度提升相匹配(可能是因为它们需要同步,可能是因为没有足够的带宽等)。因此,您只是在为无法跟上它们的资源进行线程竞争。您的场景根本不需要并行性(至少不是您尝试的方式)。

如果您想了解如何Parallel.For提高循环的性能,请考虑在循环内进行一些计算,将结果保存到数组中的独占(对于每次迭代)索引,并确保这些计算不依赖于其他迭代的结果以任何方式。

于 2013-05-09T09:04:06.200 回答
1

通过并行编程,您可以同时完成更多工作。它使您的代码并行执行。当您第一次看到并行编程时,您期望您的速度线性增加。像 4 核一样快 4 倍。

然而,这只发生在您拥有最理想的并行编程代码时。很少有算法有这个。

代码的总加速受到无法并行化的代码部分的限制。就像之前在评论和答案中所述,对于 Console.WriteLine 或数据库访问,您的线程必须同步。所以这部分不能并行化。如果您的代码中有很大一部分无法并行执行,那么该代码的执行速度甚至可能比正常循环慢。(用于同步线程的时间)。

阿姆达尔定律给了我们这个结论。

它指出无法并行化的程序的一小部分将限制并行化的整体加速

在此处阅读有关 Amdhal 定律的更多信息:

http://en.wikipedia.org/wiki/Parallel_computing

于 2013-05-09T09:10:37.720 回答
0

我在 linqpad 中尝试了您的代码,使用 for 语句得到 9 秒,使用 Parallel.For 得到 12.5 秒

当您尝试访问 I/O 资源(如数据库或控制台输出)时,您必须使用锁定机制同步线程。无论如何,我不建议并行访问数据库以进行插入或选择语句。

但是,请尝试使用此更改的代码:

 Stopwatch sw = Stopwatch.StartNew(); 
 StringBuilder str = new StringBuilder();

 for (int i = 0; i < 1000000; i++)
 {
      str.AppendLine(i.ToString());
 }

 sw.Stop();
 Console.WriteLine(sw.Elapsed);

 str = new StringBuilder();
 sw.Restart();

 Parallel.For(0,1000000,i =>
                {
                    str.AppendLine(i.ToString());
                });              

 sw.Stop();
 Console.WriteLine(sw.Elapsed);

这会将时间减少到几百毫秒。

于 2013-05-09T09:04:24.530 回答