什么时候使用Parallel.For?

问题描述 投票:0回答:4

我最近迁移到 C#.net 4。

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

但是有关于使用 Parallels 的开销的测试吗?意思是,如果我的循环只运行 10 次(并且执行很少的逻辑)——我应该避免并行吗?有什么经验法则吗?

.net c#-4.0 parallels
4个回答
6
投票

我会避免使用

Parallel.For
,除非性能是一个问题。

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


4
投票

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

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

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

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.

0
投票

引用 SQLite FAQ:“线程是邪恶的”。避开他们'

并行化对于性能很有用。应用程序性能优化是软件设计中最违反直觉的事情之一,应该非常小心地使用正确的测量工具来完成,否则它会看起来很有趣。

有些人会优化 UI 代码以在微秒而不是毫秒内响应,这显然没有价值并造成大量损害。


0
投票
可组合性必须是答案的一部分。在库中使用并行性与在应用程序中使用并行性不同,在库中,可组合性必须是优先考虑的(因为您不知道客户将如何结束使用您的代码),在应用程序中,您知道如何组合各个部分。并行代码的可组合性对于 .NET 来说并不是那么糟糕,但是当您决定矩阵乘法必须是在所有可用核心中运行的代码段时,您就使库的用户更难使用以下命令运行两种不同的算法并行矩阵乘法。事实上,只要有可能,我更喜欢在库中使用 SIMD:它会产生更少的冲突……除非您在较旧的 CPU 中混合使用 SSE 和 AVX。

© www.soinside.com 2019 - 2024. All rights reserved.