如何使用PLINQ并行化for-cycle?

时间:2014-08-24 12:47:25

标签: c# plinq

我有一项任务是使用PLINQ并行化迭代。为此,我有一个基于for-cycle的功能:

public void PointGenerator(int n, Random rnd)
{
    for (int i = 1; i <= n; i++)
    {
        x = rnd.NextDouble(); 
        y = rnd.NextDouble(); // 
        if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25)
        {
            N_0++;
        }
    }
}

如何使用PLINQ进行操作?

2 个答案:

答案 0 :(得分:5)

你可以尝试这样:

public bool Check(double x, double y)
{
    return ((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25;    
}

// ...

N_0 = Enumerable
    .Range(0, n)
    .Select(i => new { X = rnd.NextDouble(), Y = rnd.NextDouble() })
    .AsParallel()
    .Count(p => Check(p.X, p.Y));

正如Roman Dvoskin在其他答案的评论中指出的那样,Random对象不是线程安全的:

  

但是,Random对象不是线程安全的。如果您的应用程序从多个线程调用随机方法,则必须使用同步对象以确保一次只有一个线程可以访问随机数生成器。如果您不确保以线程安全的方式访问Random对象,则对返回随机数的方法的调用将返回0.

可以通过首先生成所有XY对来解决此问题。

答案 1 :(得分:3)

Parallel.ForEach上使用range方法:

var randLock = new object();
Parallel.ForEach(
    Enumerable.Range(1, n)
,   () => { // if you needed the index, you could use i instead of ()
        lock (randLock) {
            x = rnd.NextDouble(); 
            y = rnd.NextDouble();
        }
        if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25) {
            Interlocked.Increment(ref N_0);
        }
    });

请注意使用Interlocked.Increment而不是N_0++来避免并发问题。使用randLock具有相同的目的:根据文档,System.Random不是线程安全的。