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

本文关键字:循环 运行 并行 何比 顺序 | 更新日期: 2023-09-27 18:35:27

我尝试了一个非常小的例子:

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");
        }
    }
}

输出为:

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

顺序循环比 TPL 快得多!这怎么可能?据我了解,Parallel.For内的计算是并行执行的,那么它必须更快吗?

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

简单地说:对于仅迭代一百多个项目并执行一个小的数学运算,生成新线程并等待它们完成会产生比仅仅运行循环更多的开销。

据我了解,Parallel.For 内的计算将并行执行,那么它必须更快吗?

正如人们通常对计算机性能做出笼统的陈述一样,这里有更多的变量在起作用,你不能真正做出这种假设。例如,在for循环中,您只做Math.Pow,处理器可以非常快速地执行。如果这是 I/O 密集型操作,需要每个线程等待很长时间,或者即使是一系列处理器密集型操作,您也会从并行处理中获得更多收益(假设您有一个多线程处理器)。但实际上,创建和同步这些线程的开销远远大于并行性可能为您带来的任何优势。

当在循环中执行的操作成本相对较高时,并行循环处理是有益的。您在示例中所做的只是计算指数,这很简单。在这种情况下,多线程的开销远远超过您获得的收益。

这个代码示例是上面的实际证明非常好的答案。

我通过简单地通过 Thead.Sleep 阻止线程来模拟密集的处理器操作。

输出为:

    顺序循环 - 00:00
  • :09.9995500
  • 并行循环 - 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();
    }
}

并行化的开销远远大于简单地按顺序运行 Math.Pow 100 次。 其他人都这样说。

更重要的是,在顺序版本中,内存访问是微不足道的,但是对于并行版本,线程必须共享内存(resultItems),即使你有一百万个项目,这种事情也会真正杀死你。

请参阅这本关于并行编程的优秀Microsoft白皮书的第 44 页:http://www.microsoft.com/en-us/download/details.aspx?id=19222。 以下是有关该主题的MSDN杂志文章:http://msdn.microsoft.com/en-us/magazine/cc872851.aspx