博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编写高质量代码改善C#程序的157个建议——建议89:在并行方法体中谨慎使用锁...
阅读量:5236 次
发布时间:2019-06-14

本文共 1702 字,大约阅读时间需要 5 分钟。

建议89:在并行方法体中谨慎使用锁

除了建议88所提到的场合,要谨慎使用并行的情况还包括:某些本身就需要同步运行的场合,或者需要较长时间锁定共享资源的场合。
在对整型数据进行同步操作时,可以使用静态类Interlocked的Add方法,这就极大地避免了由于进行原子操作长时间锁定某个共享资源所带来的同步性能损耗。回顾建议83中的例子。

static void Main(string[] args)  {      int[] nums = new int[] { 1, 2, 3, 4 };      int total = 0;      Parallel.For
(0, nums.Length, () => { return 1; }, (i, loopState, subtotal) => { subtotal += nums[i]; return subtotal; }, (x) => Interlocked.Add(ref total, x) ); Console.WriteLine("total={0}", total); Console.ReadKey(); }

理论上,针对total的加法操作,需要使用一个同步锁,否则就无法避免一次torn read(即两次mov操作所导致的字段内存地址边界对齐问题)。FCL通过提供Interlocked类型解决了这个问题。FCL用来解决简单类型的原子性操作还提供了volatile关键字。不过这些都不是本建议所要讨论的重点。FCL现有的原子性操作为我们同步整型数据的时候,带来了性能上的提高。但是,在其他一些场合,我们却不得不考虑因为同步锁带来的损耗。

来看一个例子:

static void Main(string[] args)  {      SampleClass sample = new SampleClass();      Parallel.For(0, 10000000, (i) =>    {          sample.SimpleAdd();      });      Console.WriteLine(sample.SomeCount);  }   class SampleClass  {      public long SomeCount { get; private set; }       public void SimpleAdd()      {          SomeCount++;      }  }

这段代码的输出或许是:

8322580

显然,这与我们的期待输出10000000有很大的差距。为了保证输出正确,必须为并行中的方法体加锁(假设SampleClass是外部提供的API,无权进行源码修改在其内部加锁):

object syncObj = new object();  Parallel.For(0, 10000000, (i) =>{      lock (syncObj)      {          sample.SimpleAdd();      }  });

经过以上修改后,代码输出就正确了。但是,这段代码也带来了另外的问题。由于锁的存在,系统的开销也增加了,同步带来的线程上下文切换,使我们牺牲了CPU时间与空间性能。简单地说,就是这段代码还不如不用并行。在建议73中曾经提到过,锁其实就是让多线程变成单线程(因为同时只允许有一个线程访问资源)。所以,我们需要谨慎地对待并行方法中的同步问题。如果方法体的全部内容都需要同步运行,就完全不应该使用并行。

 

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

转载于:https://www.cnblogs.com/jesselzj/p/4743527.html

你可能感兴趣的文章
我是插件狂人,jDuang,jValidator,jModal,jGallery
查看>>
jquery的contains方法
查看>>
python3--算法基础:二分查找/折半查找
查看>>
Perl IO:随机读写文件
查看>>
linux后台运行和关闭SSH运行,查看后台任务
查看>>
cookies相关概念
查看>>
CAN总线波形中ACK位电平为什么会偏高?
查看>>
MyBatis课程2
查看>>
桥接模式-Bridge(Java实现)
查看>>
网络请求返回HTTP状态码(404,400,500)
查看>>
Spring的JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate
查看>>
Mac下使用crontab来实现定时任务
查看>>
303. Range Sum Query - Immutable
查看>>
图片加载失败显示默认图片占位符
查看>>
【★】浅谈计算机与随机数
查看>>
解决 sublime text3 运行python文件无法input的问题
查看>>
javascript面相对象编程,封装与继承
查看>>
Atlas命名空间Sys.Data下控件介绍——DataColumn,DataRow和DataTable
查看>>
Java中正则表达式的使用
查看>>
算法之搜索篇
查看>>