Parallel.For不等待所有迭代

时间:2015-01-27 14:37:02

标签: c# parallel-processing parallel.for

我正在使用遗传算法构建优化程序。我使用Parallel.For来减少时间。但它导致了一个问题,在下面的代码中是相同的:

class Program
    {
        static void Main(string[] args)
        {
            int j=0;
            Parallel.For(0, 10000000, i =>
                {
                    j++;
                });
            Console.WriteLine(j);
            Console.ReadKey();
        }
    } 

每次我运行上面的程序时,它会在0到10000000之间写入不同的j值。我猜它不会等待所有迭代完成。它传递到下一行。 我该怎么解决这个问题?任何帮助将不胜感激。谢谢。

版: Interlocked.Increment(ref j);子句解决了意外的结果,但是当我与循环的正常比较时,这个操作导致大约10倍的时间。

3 个答案:

答案 0 :(得分:5)

您可以使用最简单的Interlocked.Increment(int32)方法。

使用Parallel.For将创建多个线程,这些线程将执行相同的lambda表达式;在这种情况下,它只是j++

j++将编译为类似j = j + 1的内容,这是一个读写操作。这可能会导致不必要的行为。

j = 50

线程1正在执行j++的读取,它将获得50并将其加1。在该线程完成对j的写操作之前,另一个线程执行读操作并从j读取50,然后第一个线程完成对j的写操作,使其成为51但是第二个线程线程仍然有50个内存作为j的值,并将其加1并再次将51写回j

使用Interlocked类可确保每个操作都以原子方式进行。

答案 1 :(得分:3)

您对j的访问权限未同步。请阅读有关多线程和同步的基础书籍或教程。

Parallel.For 等待所有迭代。

使用同步(从而无法使用并行):

class Program
{
    static void Main(string[] args)
    {
        object sync = new object;
        int j=0;
        Parallel.For(0, 10000000, i =>
            {
                lock(sync)
                {
                  j++;
                }
            });
        Console.WriteLine(j);
        Console.ReadKey();
    }
} 

答案 2 :(得分:3)

Parallel.For 等待所有迭代完成。您在变量中看到意外值的原因是不同的 - 这是预期的。

基本上,Parallel.For将迭代调度到多个线程(如您所料)。但是,如果没有某种保护机制,多个线程不能共享相同的可写内存 - 如果有,则会有data race,结果在逻辑上是不确定的。这适用于所有编程语言,这是多线程的基本警告。

根据您的使用情况,您可以使用多种防护装置。他们工作的基本方式是atomic operations,您可以通过Interlocked帮助程序类访问它们。更高级别的守卫包括Monitor类,相关lock language construct和类ReaderWriterLock(及其兄弟姐妹)等类。