C#Parallel.For意外结果

时间:2014-06-07 20:37:49

标签: c# parallel-processing

我是C#的新手,在翻译我的旧DSP​​,VB6代码时,我希望利用这种语言提供的可能性。 具体来说,我试图使用并行处理来加速昂贵的计算时间。

以下是我目前正在测试的(简化)代码。

“1°并行代码确定”部分工作正常,没有问题;

“2°并行代码错误结果”部分,对我来说,应该等同于“顺序代码确定”部分比顺序版本快得多,但不会返回预期结果。

为什么呢?我哪里错了?

     double[] Omega = new double[NFreq + 1];
     double[,] SinOmT = new double[NFreq + 1, NVAL];
     double[,] CosOmT = new double[NFreq + 1, NVAL];

 double OmT;

    // 1° Parallel code OK:
      Parallel.For(0, NFreq + 1, JF =>
    {
        Omega[JF] = PI2 * Freq[JF] / Fs;
    });

    // Sequential code OK:
    for (int JF = 1; JF <= NFreq; JF++)
    {
        for (int JD = 0; JD < NVAL; JD++)
        {
            OmT = Omega[JF] * (double)(JD);
            SinOmT[JF, JD] = Math.Sin(OmT);
            CosOmT[JF, JD] = Math.Cos(OmT);
        }
    }

    // 2° Parallel code WRONG results:
    for (int JF = 1; JF <= NFreq; JF++)
    {
        Parallel.For(0, NVAL, JD =>
        {
            OmT = Omega[JF] * (double)(JD);
            SinOmT[JF, JD] = Math.Sin(OmT);
            CosOmT[JF, JD] = Math.Cos(OmT);
        });
    }

Ciao,感谢您的关注。

佛朗哥

2 个答案:

答案 0 :(得分:4)

在循环之外声明变量OmT是错误的,因为然后并行迭代会对它进行竞争并无法预测地覆盖它的值。

在C#中,你应该总是在最有意义的范围内声明变量。这适用于所有场景,而不仅仅是并行代码。

        var OmT = Omega[JF] * (double)(JD);
        SinOmT[JF, JD] = Math.Sin(OmT);
        CosOmT[JF, JD] = Math.Cos(OmT);

答案 1 :(得分:0)

变量JF被lambda表达式捕获;这意味着它将始终具有相同的值。有关更好的解释,请参阅here