我有一个简单的程序,它返回低于某个数字的素数之和。
当我在不使用TPL的情况下运行该程序时,它会给出正确的结果,但是当我使用TPL运行程序时,它会得到错误的结果。
我无法理解这有什么问题。有人可以帮忙吗?
以下是代码:
static void Main(string[] args)
{
var executionStartTime = DateTime.Now;
Console.WriteLine(GetSumOfPrimesBelowviaTPL(2000000));
Console.WriteLine("End Time: " + (DateTime.Now - executionStartTime).ToString("T"));
var a = Console.ReadLine();
}
private static long GetSumOfPrimesBelow(int number)
{
long sumOfPrimes = 0;
for (int i = 2; i < number; i++)
{
if ((i == 2 || i % 2 != 0) && (i == 3 || i % 3 != 0) && IsPrime(i))
{
sumOfPrimes += i;
}
}
return sumOfPrimes;
}
private static long GetSumOfPrimesBelowviaTPL(int number)
{
long sumOfPrimes = 0;
var primeNumbersList = new List<int>();
Parallel.For(2, number, i =>
{
if ((i == 2 || i % 2 != 0) && (i == 3 || i % 3 != 0) && IsPrime(i))
{
primeNumbersList.Add(i);
}
});
foreach (var item in primeNumbersList)
{
Console.WriteLine(item);
sumOfPrimes += item;
}
return sumOfPrimes;
}
答案 0 :(得分:1)
在你的Parallel.For中,你希望有这样的东西
lock (primeNumbersList)
{
primeNumbersList.Add(i);
}
然后它会产生相同的结果。列表不是线程友好的,写入列表可能会导致麻烦。
另外我注意到,你的算法看起来不是很有效,为什么循环两次,如果你能在你的Prallel内计算你的总和。对于
答案 1 :(得分:1)
我认为你面临的是生产者 - 消费者问题。列表类型也不是线程安全的。
不确定这是否能解决您的问题所以请试一试并告诉我。
在您的GetSumOfPrimesBelowviaTPL方法中,而不是List使用BlockingCollection。所以你的primeNumbersList不是List类型而是BlockingCollection类型。这将确保线程安全。它也比自定义锁定结构更有效。
在foreach之前写下primeNumbersList.CompleteAdding()。这将解决您的生产者 - 消费者问题。
在foreach中,不要直接使用primeNumbersList,而是使用primeNumbersList.GetConsumingEnumerable()。
所以你的方法应该是这样的。
private static long GetSumOfPrimesBelowviaTPL(int number)
{
long sumOfPrimes = 0;
var primeNumbersList = new BlockingCollection<int>();
Parallel.For(2, number, i =>
{
if ((i == 2 || i % 2 != 0) && (i == 3 || i % 3 != 0) && IsPrime(i))
{
primeNumbersList.Add(i);
}
});
primeNumbersList.CompleteAdding();
foreach (var item in primeNumbersList.GetConsumingEnumerable())
{
Console.WriteLine(item);
sumOfPrimes += item;
}
return sumOfPrimes;
}
显然,您需要包含一些名称空间。我没有测试过这种方法,所以如果有任何编译错误,请原谅我。