简体   繁体   English

LINQ中的C#并行性

[英]C# parallelism in LINQ

I would like to know if this is a safe way of calculating x in the code below. 我想知道这是否是一种在下面的代码中计算x的安全方法。

public static IEnumerable<Object> Parse(Object obj, ref int x)
{
    x += 10;
    return new List<Object>();
}

public static void Query(List<Object> obj)
{
    int x = 0;

    var result = obj
        .AsParallel()
        .Select(o => Parse(o, ref x))
        .Aggregate((a, b) => a.Concat(b));
}

This is a shortened version of my code. 这是我的代码的缩短版本。 I want the x to be some kind of a static counter for all parallel executions of Parse . 我希望x对于static counter for all parallel executions of Parse某种static counter for all parallel executions of Parse I hope this is not confusing. 我希望这不会令人困惑。

Your code has a race condition. 您的代码有竞争条件。 Even though variable x is passed by reference, it remains the same variable in all concurrent executions, so adding ten to it needs to be atomic. 即使变量x通过引用传递,它在所有并发执行中仍然是相同的变量,因此向它添加十个需要是原子的。

One way to fix this would be using Interlocked.Add method instead of += : 解决此问题的一种方法是使用Interlocked.Add方法而不是+=

public static IEnumerable<Object> Parse(Object obj, ref int x)
{
    Interlocked.Add(ref x, 10);
    return new List<Object>();
}

Definitely not safe . 绝对不安全 You need to use the Interlocked class. 您需要使用Interlocked类。

public static IEnumerable<Object> Parse(Object obj, ref int x)
{
    Interlocked.Add(ref x, 10);
    return new List<Object>();
}

I would suggest a different approach to tackle the issue, as suggested earlier introducing a synchronization construct in the Parallel code would impact its working, if you still need it then your original code need something like Interlocked / lock to make it thread safe, however 我建议采用不同的方法来解决这个问题,正如前面所说的,在并行代码中引入同步构造会影响它的工作,如果你仍然需要它,那么你的原始代码需要像Interlocked / lock之类的东西来使它的线程安全,不过

A better way would be each thread have a local counter and aggregate that at the end, something like this: 一个更好的方法是每个线程都有一个本地计数器并在最后聚合,如下所示:

public class MyClass
{
  public int x;
  public object o;
}

public static IEnumerable<MyClass> Parse(Object obj)
{
    MyClass c = new MyClass();
    c.x += 10;
    c.o  = <some new object>
    // Add c to instance of List<MyClass>
    return new List<MyClass>();
}

public static void Query(List<Object> obj)
{          
    var result = obj
        .AsParallel()
        .Select(o => Parse(o))

   // result is of type IEnumerable<MyClass>

   var sum = result.Sum(a=>a.x);

   var aggregate = result.Aggregate((a, b) => a.o.Concat(b.o));
}

This is a lock / synchronization free solution which has no performance hit and there's no race condition. 这是一个无锁/同步解决方案,没有性能损失,也没有竞争条件。 Always for threading, try to make things local for a thread and later on apply a function like sum for every individual thread variable. 始终用于线程,尝试为线程创建局部内容,然后为每个单独的线程变量应用sum之类的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM