Go并发,虽然官方推荐 channel,但到底是channel还是锁?( 二 )

  • 用户小明:创建了存100、取20、查余额的3个请求,每个请求得到响应后,再把下一个请求写入到reqCh 。
  • 用户小刚:流程和小明相同,但存100取200,造成取钱操作失败,他查询下自己又多少钱,得到100 。
  • main函数最后使用WaitGroup等待小明、小刚结束后退出 。
    下面是运行结果:
    【Go并发,虽然官方推荐 channel,但到底是channel还是锁?】$ go run channel_map.goxiaogang deposite 100 successxiaoming deposite 100 successxiaogang withdraw 200 failedxiaoming withdraw 20 successxiaogang has 100xiaoming has 80Bank exit这一遭搞完,发现啥没有?用Mutex直接加锁、解锁完事了,但channel搞出来一坨,是不是用channel解决这个问题不太适合?是的 。对于当前这个问题,和Mutex的方案相比,channel的方案显的有点“重”,不够简洁、高效、易用 。
    但这个例子展示了3点:
    1. 使用channel解决并发问题的核心在于关注数据的流动
    2. channel不一定是某个并发问题最好的解决方案
    3. map在并发中,可以不用锁进行保护,而是使用channel
    现在,回到了开篇的问题:同一个并发问题,你是用channel解决,还是用mutex解决?下面,一起看看怎么选择 。
    channel和mutex的选择面对一个并发问题的时候,应当选择合适的并发方式:channel还是mutex 。选择的依据是他们的能力/特性:channel的能力是让数据流动起来,擅长的是数据流动的场景,《Channel or Mutex》中给了3个数据流动的场景:
    1. 传递数据的所有权,即把某个数据发送给其他协程
    2. 分发任务,每个任务都是一个数据
    3. 交流异步结果,结果是一个数据
    mutex的能力是数据不动,某段时间只给一个协程访问数据的权限擅长数据位置固定的场景,《Channel or Mutex》中给了2个数据不动场景:
    1. 缓存
    2. 状态,我们银行例子中的map就是一种状态
    提供解决并发问题的一个思路:
    1. 先找到数据的流动,并且还要画出来,数据流动的路径换成channel,channel的两端设计成协程
    2. 基于画出来的图设计简要的channel方案,代码需要做什么
    3. 这个方案是不是有点复杂,是不是用Mutex更好一点?设计一个简要的Mutex方案,对比&选择易做的、高效的
    channel + mutex思维面对并发问题,除了channel or mutex,你还有另外一个选择:channel plus mutex 。
    一个大并发问题,可以分解成很多小的并发问题,每个小的并发都可以单独选型:channel or mutex 。但对于整个大的问题,通常不是channel or mutex,而是channel plus mutex 。


    推荐阅读