并行问题

Moc*_*aiz 0 c# multithreading parallel.foreach

我已经编写了3种不同的计算整数数组之和的方法,但是,我得到了第三种方法的不同结果.

初始化:

        int n = 100;
        int[] mArray = new int[n];
        for (int i = 0; i < mArray.Length; i++)          
            mArray[i] = 1;
Run Code Online (Sandbox Code Playgroud)

第一:

        int sum1 = mArray.Sum();
        Console.WriteLine("sum1 " + sum1);
Run Code Online (Sandbox Code Playgroud)

第二:

        int sum2 = 0;
        for (int i = 0; i < mArray.Length; i++)
            sum2 += mArray[i];
        Console.WriteLine("sum2 " + sum2);
Run Code Online (Sandbox Code Playgroud)

第三:

        int sum3 = 0;
        Parallel.ForEach(mArray, item =>
        {
            sum3 += item;
        });
        Console.WriteLine("sum3 " + sum3);
Run Code Online (Sandbox Code Playgroud)

显然,3种方法给出了如下所示的相同输出:

然而,当n增加(例如,n = 30000)时,第三种方法给出了令人惊讶的错误结果

注意:我使用ConcurrentBag测试了这些方法,这是一个线程安全的集合.我想,没有溢出问题.代码在Windows 10 x64计算机(Intel核心I-7 @ 3.30ghz)上进行测试

理解为什么Parallel.For的行为不同会很有趣.

Nic*_*ick 5

问题是sum3您使用时可以通过多个线程访问Parallel.ForEach.sum3 += item;通常会涉及三个操作:1.读取sum3临时存储的值.2.增加该存储的值item; 3.将结果存回sum3.

当同时存在多个线程时,操作很可能会混合.例如,如果您有两个线程A和B,两者都可以读取相同的值sum3,然后进行添加并将新值存储回来.

要解决此问题,您需要保护您的访问权限sum3.代码应该如下所示:

 object objLock = new object();
 int sum3 = 0;
 Parallel.ForEach(mArray, item =>
 {
     lock (objLock) { sum3 += item; }
 });
 Console.WriteLine("sum3 " + sum3);
Run Code Online (Sandbox Code Playgroud)

但是,这将完全否定并行执行的效果.