我正在尝试使用.NET 4中的新并行工具,通过蒙特卡罗方法计算Pi值。
(实际算法并不是很重要,但为了清晰起见,在此说明:
- 在单位正方形内选择
numIterations
个随机点。 - 计算这些点中有多少个位于由该正方形界定的圆内(即距正方形中心小于0.5的点)。
- 然后,对于非常大的
numIterations
,PI=4 * iterationsInsideCircle / numIterations
。)
我有一个int ThrowDarts(int numDarts)
方法,它在单位正方形(如上所述)内选择numDarts
个随机点,并返回位于单位圆内的点数:
protected static int ThrowDarts(int iterations)
{
int dartsInsideCircle = 0;
Random random = new Random();
for (int iteration = 0; iteration < iterations; iteration++)
{
double pointX = random.NextDouble() - 0.5;
double pointY = random.NextDouble() - 0.5;
double distanceFromOrigin = Math.Sqrt(pointX*pointX + pointY*pointY);
bool pointInsideCircle = distanceFromOrigin <= 0.5;
if (pointInsideCircle)
{
dartsInsideCircle++;
}
}
return dartsInsideCircle;
}
基本上,在我的不同实现中(每个实现都使用不同的并行机制),我正在编写将飞镖抛入圆圈内并计数的不同方式。
例如,我的单线程实现只是:
protected override int CountInterationsInsideCircle()
{
return ThrowDarts(_numInterations);
}
我也有一种用于我的并行算法之一的方法:
protected override int CountInterationsInsideCircle()
{
Task<int>[] tasks = new Task<int>[_numThreads];
for (int i = 0; i < _numThreads; i++)
{
tasks[i] = Task.Factory.StartNew(() => ThrowDarts(_numInterations/_numThreads));
}
int iterationsInsideCircle = 0;
for (int i = 0; i < _numThreads; i++)
{
iterationsInsideCircle += tasks[i].Result;
}
return iterationsInsideCircle;
}
希望你能理解这个情况。
这里,我遇到了一个难题。我正在编写的
Parallel.For
版本会导致大量的上下文切换。以下是代码: protected override int CountInterationsInsideCircle()
{
ConcurrentBag<int> results = new ConcurrentBag<int>();
int result = 0;
Parallel.For(0, _numInterations,
// initialise each thread by setting it's hit count to 0
() => 0,
//in the body, we throw one dart and see whether it hit or not
(iteration, state, localState) => localState + ThrowDarts(1),
// finally, we sum (in a thread-safe way) all the hit counts of each thread together
results.Add);
foreach(var threadresult in results)
{
result+=threadresult;
}
return result;
}
使用
Parallel.For
版本确实可以工作,但速度非常慢,因为前面提到的上下文切换(在前两种方法中不会发生)。有没有人能够告诉我为什么会发生这种情况?