简体   繁体   English

顺序循环如何比C#中的并行循环运行得更快?

[英]How does sequential loop run faster than Parallel loop in C#?

I tried a very minimal example: 我尝试了一个非常小的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace TPLExample {
    class Program {
        static void Main(string[] args) {
            int[] dataItems = new int[100];
            double[] resultItems = new double[100];

            for (int i = 0; i < dataItems.Length; ++i) {
                dataItems[i] = i;
            }

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Reset();
            stopwatch.Start();
            Parallel.For(0, dataItems.Length, (index) => {
                resultItems[index] = Math.Pow(dataItems[index], 2);
            });
            stopwatch.Stop();
            Console.WriteLine("TPL Time elapsed: {0}", stopwatch.Elapsed);

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < dataItems.Length; ++i) {
                resultItems[i] = Math.Pow(dataItems[i], 2);
            }
            stopwatch.Stop();
            Console.WriteLine("Sequential Time elapsed: {0}", stopwatch.Elapsed);

            WaitForEnterKey();
        }

        public static void WaitForEnterKey() {
            Console.WriteLine("Press enter to finish");
            Console.ReadLine();
        }

        public static void PrintMessage() {
            Console.WriteLine("Message printed");
        }
    }
}

The output was: 输出是:

TPL Time elapsed: 00:00:00.0010670
Sequential Time elapsed: 00:00:00.0000178
Press enter to finish

The sequential loop is way faster than TPL! 顺序循环比TPL快! How is this possible? 这怎么可能? From my understanding, calculation within the Parallel.For will be executed in parallel, so must it be faster? 根据我的理解, Parallel.For计算将Parallel.For执行,所以它必须更快吗?

Simply put: For only iterating over a hundred items and performing a small mathematical operation, spawning new threads and waiting for them to complete produces more overhead than just running through the loop would. 简单地说:对于只迭代超过一百个项目并执行一个小的数学运算,产生新线程并等待它们完成会产生比仅仅通过循环运行更多的开销。

From my understanding, calculation within the Parallel.For will be executed in parallel, so must it be faster? 根据我的理解,Parallel.For中的计算将并行执行,所以它必须更快吗?

As generally happens when people make sweeping statements about computer performance, there are far more variables at play here, and you can't really make that assumption. 通常情况下,当人们对计算机性能进行彻底的陈述时,这里有更多的变量,你无法真正做出这样的假设。 For example, inside your for loop, you are doing nothing more than Math.Pow , which the processor can perform very quickly. 例如,在for循环中,您只做Math.Pow ,处理器可以非常快速地执行。 If this were an I/O intensive operation, requiring each thread to wait a long time, or even if it were a series of processor-intensive operations, you would get more out of Parallel processing (assuming you have a multi-threaded processor). 如果这是一个I / O密集型操作,要​​求每个线程等待很长时间,或者即使它是一系列处理器密集型操作,您将获得更多的并行处理(假设您有一个多线程处理器) 。 But as it is, the overhead of creating and synchronizing these threads is far greater than any advantage that parallelism might give you. 但事实上,创建和同步这些线程的开销远远大于并行性可能给你的任何优势。

Parallel loop processing is beneficial when the operation performed within the loop is relatively costly. 当在循环内执行的操作相对昂贵时,并行循环处理是有益的。 All you're doing in your example is calculating an exponent, which is trivial. 你在你的例子中所做的只是计算指数,这是微不足道的。 The overhead of multithreading is far outweighing the gains that you're getting in this case. 多线程的开销远远超过你在这种情况下获得的收益。

This code example is practical proof really nice answers above. 这个代码示例是实际证明上面非常好的答案。

I've simulated intensive processor operation by simply blocking thread by Thead.Sleep. 我通过Thead.Sleep简单地阻止线程来模拟密集处理器操作。

The output was: 输出是:

  • Sequential Loop - 00:00:09.9995500 顺序循环 - 00:00:09.9995500
  • Parallel Loop - 00:00:03.0347901 并联循环 - 00:00:03.0347901

_ _

class Program
{
    static void Main(string[] args)
    {
        const int a = 10;

        Stopwatch sw = new Stopwatch();
        sw.Start();

        //for (long i = 0; i < a; i++)
        //{
        //    Thread.Sleep(1000);
        //}

        Parallel.For(0, a, i =>
        {
            Thread.Sleep(1000);
        });

        sw.Stop();

        Console.WriteLine(sw.Elapsed);

        Console.ReadLine();
    }
}

The overhead of parallelization is far greater than simply running Math.Pow 100 times sequentially. 并行化的开销远远大于简单地按顺序运行Math.Pow 100次。 The others have said this. 其他人都这么说了。

More importantly, though, the memory access is trivial in the sequential version, but with the parallel version, the threads have to share memory (resultItems) and that kind of thing will really kill you even if you have a million items. 但更重要的是,内存访问在顺序版本中是微不足道的,但是对于并行版本,线程必须共享内存(resultItems),即使你有一百万个项目,这种东西也会真的杀了你。

See page 44 of this excellent Microsoft whitepaper on parallel programming: http://www.microsoft.com/en-us/download/details.aspx?id=19222 . 请参阅这篇关于并行编程的优秀 Microsoft白皮书的第44页: http//www.microsoft.com/en-us/download/details.aspx?id = 19222 Here is an MSDN magazine article on the subject: http://msdn.microsoft.com/en-us/magazine/cc872851.aspx 这是一篇关于这个主题的MSDN杂志文章: http//msdn.microsoft.com/en-us/magazine/cc872851.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM