我有这段代码:
int totalData = result.Data.Count;
int count = 0;
Parallel.ForEach(result.Data, data =>
{
try
{
EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
count++;
EntityImported(importedEntity, count, totalData);
}
catch (Exception e)
{
exceptions.Enqueue(e);
}
});
EntityImported是一个事件,应该说明已经处理了多少实体,以及我应该处理多少实体。我担心的是在lambda内增加count的线程安全性,以及你建议采用哪些步骤来确保事件始终使用count变量的正确值来触发。
答案 0 :(得分:9)
目前它根本不是线程安全的。
您可以改为使用Interlocked.Increment(ref count)
,但 更好地拥有" local"每个线程的值,并在最后总结它们。这样,除了分配要处理的项目之外,您不需要任何类型的跨线程数据流。
Parallel.ForEach
的重载是为了这个目的而设计的 - 请查看文档底部附近的示例,因为它正在做非常类似的事情你的代码。 (它维护一个本地计数,然后在最后对计数求和。)不幸的是,由于你需要在每次迭代时引发事件的方式,这对你的特定情况没有帮助 - 但通常那是一种更好的方法。
在这种情况下,您应该在事件提升代码中使用Interlocked.Increment
的结果:
Parallel.ForEach(result.Data, data =>
{
try
{
EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
int newCount = Interlocked.Increment(ref count);
EntityImported(importedEntity, newCount, totalData);
}
catch (Exception e)
{
exceptions.Enqueue(e);
}
});
这样就会为每个计数引发一个事件(因此一个为0,一个为1,一个为2等)。