[英]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.