C# 第三方物流无法使用Parallel.For和List产生正确的结果<;T>;
我有一个简单的程序,返回低于某个数的素数之和 当我不使用TPL运行该程序时,它会给出正确的结果,但当我使用TPL运行该程序时,它会给出错误的结果 我不明白这有什么问题。有人能帮忙吗 代码如下:C# 第三方物流无法使用Parallel.For和List产生正确的结果<;T>;,c#,task-parallel-library,.net-4.5,C#,Task Parallel Library,.net 4.5,我有一个简单的程序,返回低于某个数的素数之和 当我不使用TPL运行该程序时,它会给出正确的结果,但当我使用TPL运行该程序时,它会给出错误的结果 我不明白这有什么问题。有人能帮忙吗 代码如下: static void Main(string[] args) { var executionStartTime = DateTime.Now; Console.WriteLine(GetSumOfPrimesBelowviaTPL(2000000)); Console.Write
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;
}
static void Main(字符串[]args)
{
var executionStartTime=DateTime.Now;
控制台写入线(GetSumOfPrimesBelowviaTPL(2000000));
WriteLine(“结束时间:”+(DateTime.Now-executionStartTime.ToString(“T”));
var a=Console.ReadLine();
}
private static long getsumof primesbelow(整数)
{
长时间累计时间=0;
for(int i=2;i
{
如果((i==2 | | i%2!=0)&&(i==3 | | i%3!=0)&&IsPrime(i))
{
素数列表。添加(i);
}
});
foreach(primeNumbersList中的变量项)
{
控制台写入线(项目);
时间总和+=项目;
}
返回时间;
}
在您的并行程序中。例如,您想要这样的程序
lock (primeNumbersList)
{
primeNumbersList.Add(i);
}
然后它将产生相同的结果。列表不是线程友好的,这样写入列表可能会带来麻烦
我还注意到,你的算法似乎不是很有效,如果你能在Prallel中计算出你的和,为什么要循环两次呢。此外,列表类型不是线程安全的 不太确定这是否能解决你的问题,所以请尝试一下,让我知道
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;
}
primesbelowviatpl私有静态长GetSumOfPrimesBelowviaTPL(整数)
{
长时间累计时间=0;
var primeNumbersList=new BlockingCollection();
Parallel.For(2,number,i=>
{
如果((i==2 | | i%2!=0)&&(i==3 | | i%3!=0)&&IsPrime(i))
{
素数列表。添加(i);
}
});
PrimeNumberList.CompleteAdding();
foreach(PrimeNumberList.GetConsumingEnumerable()中的变量项)
{
控制台写入线(项目);
时间总和+=项目;
}
返回时间;
}
显然,您需要包含一些名称空间。我还没有测试过这个方法,所以如果有任何编译错误,请原谅。常规列表不是线程安全的,您正在(可能)从多个线程向一个添加项。您可能需要锁定、并发收集或(甚至更好的)PLINQ。@PatrykĆwiek您可以建议如何在这种特殊情况下实现PLINQ,或者可以作为如何在这种情况下使用PLINQ的链接。我只能在这里找到Linq 2 Sql for PLINQ的链接:
ParallelEnumerable.Range(2,数字-2)。其中(x=>(x==2 | | x%2!=0)&&(x==3 | | x%3!=0)&&IsPrime(x)).Sum()代码>谢谢@PatrykĆwiek,但是上面代码的问题是它接受一系列整数,并以整数的形式返回总和,这在我的例子中是不存在的。因为范围很大,结果肯定会是一个长的(至少)循环两次,因为sum变量将被两个或多个线程修改,它可能被一个或多个线程覆盖another@NaveedButt我可能错了,但感觉如果你必须对素数集合使用某种锁定,对sum变量使用某种锁定可能更有效。我认为你可以使用Interlocked。为此添加。我已将@samar的答案标记为正确答案,因为我使用的是内置类,而不是自己实现锁。我使用了你的代码,它工作起来很有魅力:)谢谢你花了这么多时间。我认为您的答案是正确的,因为它通过使用一些内置类而不是实现自定义锁定,使您对TPL有了更多的了解:)没问题。很高兴我能帮忙。:)