C# 第三方物流无法使用Parallel.For和List产生正确的结果<;T>;

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

我有一个简单的程序,返回低于某个数的素数之和

当我不使用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;
}
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中计算出你的和,为什么要循环两次呢。此外,列表类型不是线程安全的

不太确定这是否能解决你的问题,所以请尝试一下,让我知道

  • 在GetSumOfPrimesBelowviaTPL方法中,使用BlockingCollection代替List。因此,primeNumbersList将不是列表类型,而是BlockingCollection类型。这将确保线程安全。此外,它比自定义锁定构造更有效

  • 在foreach之前写入primeNumbersList.CompleteAdding()。这将解决您的生产者-消费者问题

  • 在foreach中,不要直接使用PrimeNumberList,而是使用PrimeNumberList.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;
    }
    
    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有了更多的了解:)没问题。很高兴我能帮忙。:)