如何正确实现Parallel.ForEach、锁定和进度报告我缺少有关锁定内容的内容。下面的例子在threadCount=1时计数为1000,但threadCount>1时threadCount不计数。正确的方法是什么?类程序{staticvoidMain(){varprogress=newProgress();varids=Enumerable.Range(1,10000);var线程数=2;Parallel.ForEach(ids,newParallelOptions{MaxDegreeOfParallelism=threadCount},id=>{progress.CurrentCount++;});Console.WriteLine("线程:{0},计数:{1}",threadCount,progress.CurrentCount);控制台.ReadKey();}}内部类Progress{privateObject_lock=newObject();私人诠释_currentCount;publicintCurrentCount{get{lock(_lock){return_currentCount;}}设置{锁(_lock){_currentCount=值;}}}}从多个线程调用(共享计数变量)count++类的一个常见问题是可能会发生此事件序列:线程A读取计数值。线程B读取count的值。线程A递增其本地副本。线程B递增其本地副本。线程A将增加的值写回计数。线程B将增加的值写回计数。这样,线程A写入的值就被线程B覆盖了,所以这个值实际上只增加了一次。您的代码在操作1,2(get)和5,6(set)周围添加了锁,但这并不能阻止有问题的事件序列。您需要做的是锁定整个操作,这样当线程A递增该值时,线程B根本无法访问它:lock(progressLock){progress.CurrentCount++;如果你知道你只需要递增,你可以在Progress上创建一个包装器来包装这个方法的方法。老问题,但我认为有更好的答案。您可以使用Interlocked.Increment(refprogress)来报告进度,这样您就不必担心将写入操作锁定为进度。最简单的解决方案实际上是用字段替换属性,并锁定{++progress.CurrentCount;}(我个人比较喜欢先自增后自增的样子,因为“++.”的东西在我脑后发生了冲突!不过当然后自增会起作用。)这样就会有added减少开销和争用的好处,因为更新字段比调用更新它的方法更快。当然,把它封装成一个属性也能有好处。IMO,因为字段和属性语法是相同的,所以当属性自动实现或等效时,在字段上使用属性的唯一好处是当您有一个场景时,您可能想要部署一个程序集,而不必重新组装和部署依赖项。否则,您也可以使用更快的字段!如果您需要检查值或添加副作用,您可以将字段转换为属性并重新构建。因此,在许多实际情况下,使用字段不会受到惩罚。然而,我们生活在一个许多开发团队教条式运作的时代,并使用像StyleCop这样的工具来强化他们的教条主义。与编码人员不同,这些工具不够智能,无法判断何时使用字段是可以接受的,因此“即使对于StyleCop检查也很简单的规则”变成了“将字段封装为属性”、“不要使用公共字段”等等。..从属性中删除锁定语句并修改主体:objectsync=newobject();Parallel.ForEach(ids,newParallelOptions{MaxDegreeOfParallelism=threadCount},id=>{lock(sync)progress.CurrentCount++;});这里的问题是++不是原始的——一个线程可以在另一个读取该值的线程之间读取和递增一个值,它存储(现在不正确的)递增的值。事实上,包含int的属性可能更复杂。例如线程1线程2读取5。.读5。写6写6!.setter和getter周围的锁无济于事,因为没有什么可以阻止它们被乱序调用。通常,我建议使用Interlocked.Increment,但不能将其与属性一起使用。相反,您可以公开_lock并让锁块环绕progress.CurrentCount++;称呼。最好将任何数据库或文件系统操作存储在本地缓冲区变量中而不是锁定它。锁定会降低性能。以上就是C#学习教程:如何正确执行Parallel.ForEach,加锁和进度报告分享。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,并不代表侵权,如有侵权,请点击右边联系管理员删除。如需转载请注明出处:
