Parallel.ForEach不更新共享变量
具有以下代码,我如何更新共享变量?Parallel.ForEach不更新共享变量
List<Person> list = new List<Person> {new Person {Age = 1}, new Person {Age = 2}, new Person {Age = 5}};
long total = 0;
Parallel.ForEach(list,() => 0, (person, loop, subtotal) =>
{
Add(person, subtotal);
return subtotal;
},
finalResult => Interlocked.Add(ref total, finalResult)
);
public static void Add(Person person, int shared)
{
// Do some work
shared =+ person.Age;
}
对于共享某种原因,回来为0
共享返回为0,因为它是作为0发送的,并且是按值传递的。您需要使用ref关键字,或以其他方式解决此行为(静态变量)。
public static void Add(Person person, ref int shared)
{
// Do some work
shared =+ person.Age;
}
它看起来像你也有一个问题,你正在使用'= +'来代替'+ ='。
public static void Add(Person person, ref int shared)
{
// You likely meant to do this.
shared += person.Age;
}
现在它返回最后一个..不是所有年龄的总和 – BobSwanson
大概你打算使用+ =?正如你设置分享到Age的正面价值? –
啊,那工作,它需要锁吗?因为它是共享的? – BobSwanson
同样的原因,将不会在“常规” C#代码工作...整数是值类型,所以你需要做的参数REF参数。否则,你只是递增本地副本。此外,您应该使用Interlocked.Increment而不是+ =,否则可能会遇到线程问题,因为+ =不一定是原子。
更改了一下你的代码,你会预期的结果:
static void Main(string[] args)
{
List<Person> persons = new List<Person>
{
new Person { Age = 1 },
new Person { Age = 2 },
new Person { Age = 5 }
};
long total = 0;
Parallel.ForEach(persons, person => Add(person, ref total));
Console.WriteLine(total);
Console.ReadKey();
}
public static void Add(Person person, ref long shared)
{
// since here you access a shared variabe, we
// can use the Interlocked class in order our operation
// to be atomic.
Interlocked.Add(ref shared, person.Age);
}
总有误。这是不同的每一次 – BobSwanson
@BobSwanson你是正确的!请参阅我的编辑。 – Christos
如果我的共享不是int或long,而是一个小数,我会用lock()来代替吗? – BobSwanson
试试这个
int sum = list.AsParallel().Sum(person => person.Age);
结果将是相同的,更少的代码将被使用。
即使修复'ref小计问题',这也不会起作用。你有一个非常明显的竞争条件。你正在不断更新和阅读价值。 – Jonesopolis
那我该如何跟踪一个共享变量呢? – BobSwanson
@BobSwanson首先不要将总和并行化。这会比仅仅在一个线程中汇总值慢得多。除了更快,它也会更简单,更容易出错,更易于维护等。 – Servy