何时使用Parallel.For?

时间:2010-09-15 08:22:54

标签: .net c#-4.0 parallels

我最近搬到了C#.net 4。

我喜欢Parallel.For,但不确定何时使用以及何时不使用。 我知道订单对我来说并不重要 - 我会用它。

但是有没有关于使用Parallels的开销的测试?意思是,如果我的循环只运行10次(并执行非常少的逻辑) - 我应该避免使用Parallels吗?有没有拇指规则?

3 个答案:

答案 0 :(得分:4)

除非性能问题,否则我会避免使用Parallel.For

编写并发运行的代码通常比编写单线程代码更难。此外,如果由于并发问题而导致错误,则可能难以对其进行调试。例如,错误可能仅在有时发生,并且不易重现。除非您特别需要提高性能,否则我建议您保持简单并在单个线程上使用普通循环。

答案 1 :(得分:1)

Parallel.For循环使用ThreadPool通过每次循环迭代调用一次委托来执行循环中的工作。

Parallel.For如何工作的一般概念可以表示如下:

public static void MyParallelFor(int inclusiveLowerBound, int exclusiveUpperBound, Action<int> body)
{
    // Get the number of processors, initialize the number of remaining
    // threads, and set the starting point for the iteration.
    int numProcs = Environment.ProcessorCount;
    int remainingWorkItems = numProcs;
    int nextIteration = inclusiveLowerBound;
    using (ManualResetEvent mre = new ManualResetEvent(false))
    {
        // Create each of the work items.
        for (int p = 0; p < numProcs; p++)
        {
            ThreadPool.QueueUserWorkItem(delegate
            {
                int index;
                while ((index = Interlocked.Increment(ref nextIteration) - 1) < exclusiveUpperBound)
                    body(index);

                if (Interlocked.Decrement(ref remainingWorkItems) == 0)
                    mre.Set();
            });
        }
        // Wait for all threads to complete.
        mre.WaitOne();
    }
}

Parallel.For返回ParallelLoopResult值类型,其中包含已完成循环的详细信息。其重载之一如下:

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);

重要的是要意识到并行执行并不总是比串行执行更快。要决定是否使用并行,您必须估计每次循环迭代所需的工作量。如果循环执行的实际工作相对于线程同步成本较小,则最好使用普通循环。

这是串行循环性能比并行更快的例子之一:

static void Main(string[] args)
{
    Action<int> action = new Action<int>(SimpleMethod);

    // ordinary For loop performance estimation
    var sw = Stopwatch.StartNew();

    for(int i = 0; i < 1000; i++)
        action(i);

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);

    // parallel For loop performance estimation
    sw = Stopwatch.StartNew();

    Parallel.For(0, 1000, action);

    Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
}

static void SimpleMethod(int index)
{
    int d = 1;
    int result = index / d;
}

<强>输出:

0.0001963 sec.
0.0346729 sec.

答案 2 :(得分:0)

引用SQLite常见问题解答:'Threads are evil。避免他们'

并行化对性能很有用。应用程序性能优化是软件设计中最直观的事情之一,应该使用正确的测量工具进行极其谨慎的操作,否则它看起来会很有趣。

有些人会优化UI代码,以微秒而不是毫秒的速度进行响应,显然没有任何价值并造成大量损害。