如何做正确的Parallel.ForEach,锁定和进度报告 [英] How to do proper Parallel.ForEach, locking and progress reporting
问题描述
我想实施 Parallel.ForEach
模式,跟踪进展,但我没有关于锁的东西。下面的例子计数到1000时, = THREADCOUNT 1
,但不能当经纬
> 1.什么是正确的办法做到这一点?
类节目
{
静态无效的主要()
{
变种进度=新进展();
VAR IDS = Enumerable.Range(1,10000);
VAR THREADCOUNT = 2;
Parallel.ForEach(IDS,新ParallelOptions {MaxDegreeOfParallelism = THREADCOUNT},ID => {progress.CurrentCount ++;});
Console.WriteLine(线程:{0},次数:{1},经纬,progress.CurrentCount);
Console.ReadKey();
}
}
内部类进步
{
私有对象_lock =新的对象();
私人诠释_currentCount;
公众诠释CURRENTCOUNT
{
得到
{
锁(_lock)
{
返回_currentCount;
}
}
组
{
锁(_lock)
{
_currentCount =价值;
}
}
}
}
通常的问题,呼吁像计数++
从多个线程(它们共享计数
变量)是这一系列事件可能发生:
- 线程A读
计数$的价值C $ C>。
- 线程b读取
计数
的值。 - 线程A增加它的本地副本。
- 线程b增加它的本地副本。
- 线程A写入递增值回
计数
。 - 线程b写入递增值回
计数
。
这方式,由线程A所写的值由线程b覆盖,所以价值实际递增一次。
您的代码将围绕操作1锁,2( GET
)和5,6(设置
),但什么也不做,以防止事件的问题的顺序。
您需要做的是要锁定整个操作,这样当线程A是递增的价值,线程b不能在所有访问:
锁(progressLock)
{
progress.CurrentCount ++;
}
如果你知道你只需要递增,您可以在创建方法进度
封装了这一点。
I'm trying to implement the Parallel.ForEach
pattern and track progress, but I'm missing something regarding locking. The following example counts to 1000 when the threadCount = 1
, but not when the threadCount
> 1. What is the correct way to do this?
class Program
{
static void Main()
{
var progress = new Progress();
var ids = Enumerable.Range(1, 10000);
var threadCount = 2;
Parallel.ForEach(ids, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, id => { progress.CurrentCount++; });
Console.WriteLine("Threads: {0}, Count: {1}", threadCount, progress.CurrentCount);
Console.ReadKey();
}
}
internal class Progress
{
private Object _lock = new Object();
private int _currentCount;
public int CurrentCount
{
get
{
lock (_lock)
{
return _currentCount;
}
}
set
{
lock (_lock)
{
_currentCount = value;
}
}
}
}
The usual problem with calling something like count++
from multiple threads (which share the count
variable) is that this sequence of events can happen:
- Thread A reads the value of
count
. - Thread B reads the value of
count
. - Thread A increments its local copy.
- Thread B increments its local copy.
- Thread A writes the incremented value back to
count
. - Thread B writes the incremented value back to
count
.
This way, the value written by thread A is overwritten by thread B, so the value is actually incremented only once.
Your code adds locks around operations 1, 2 (get
) and 5, 6 (set
), but that does nothing to prevent the problematic sequence of events.
What you need to do is to lock the whole operation, so that while thread A is incrementing the value, thread B can't access it at all:
lock (progressLock)
{
progress.CurrentCount++;
}
If you know that you will only need incrementing, you could create a method on Progress
that encapsulates this.
这篇关于如何做正确的Parallel.ForEach,锁定和进度报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!