锁实现与 Channel 实现的区别?

2019-03-27 15:48:19 +08:00
 index90

最近在读 gRPC 的源码,以下代码截取自 grpc@V1.19.0/balancer_conn_wrappers.go 文件第 118 行。

// watcher balancer functions sequentially, so the balancer can be implemented
// lock-free.
func (ccb *ccBalancerWrapper) watcher() {
	for {
		select {
		case t := <-ccb.stateChangeQueue.get():
			ccb.stateChangeQueue.load()
			select {
			case <-ccb.done:
				ccb.balancer.Close()
				return
			default:
			}
			ccb.balancer.HandleSubConnStateChange(t.sc, t.state)
		case t := <-ccb.resolverUpdateCh:
			select {
			case <-ccb.done:
				ccb.balancer.Close()
				return
			default:
			}
			ccb.balancer.HandleResolvedAddrs(t.addrs, t.err)
		case <-ccb.done:
		}

		select {
		case <-ccb.done:
			ccb.balancer.Close()
			ccb.mu.Lock()
			scs := ccb.subConns
			ccb.subConns = nil
			ccb.mu.Unlock()
			for acbw := range scs {
				ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain)
			}
			return
		default:
		}
	}
}

关于这段代码,我理解是,隐藏 ccb.balancer 的方法调用,转为以 channel 信号触发。其目的是使得 balancer 的方法在实现时不需要考虑并发问题。

我的问题是,这里如果给 balancer 的方法调用都加互斥锁,也能实现同样的目的,那么用 channel 还有什么好处呢?有哪些地方我没有考虑到的,恳请大神们指正。

3570 次点击
所在节点    Go 编程语言
5 条回复
xrlin
2019-03-27 17:34:55 +08:00
使用 select 实现同时监听多个 channel 信号,而且使用锁在尝试加锁 Lock 时可能会阻塞,在尝试解锁 Unlock 时可能会触发异常,使用 channel 免去了各种情况都处理,而且可阅读性更强。

channel 的那边实现也是有锁的,channel 还可以实现数据的分发,这些在需要通信的场景下比锁好用多了。
owenliang
2019-03-27 18:02:00 +08:00
收敛逻辑在一个协程,这无疑是可读性最高的,最好维护的。

你说的玩锁的方法,一般存在于 c++中,shared_ptr+lock 保证单个资源的同步,但带来的坏处就是并发很复杂,很难看懂。
index90
2019-03-27 18:03:09 +08:00
@xrlin 如果其中一个 channel 在处理中,其他 channel 也会被阻塞,这个和 Lock 类似。

不过也可以实现队列:ccb.stateChangeQueue,来避免阻塞。

Unlock 会触发异常,这个会产生什么异常?使用 channel 可读性更强,目前还没习惯,可能思维还没转换过来。

就为实现“顺序调用对象的 function ”这个问题上,我只是觉得用锁实现的话,代码量会少一点。

上面示例之所以非使用 channel 不可,我觉得是因为 ccb.stateChangeQueue 需要非阻塞,所以要用 Channel,不知道我理解是否正确?
xrlin
2019-03-27 19:11:48 +08:00
@index90 Lock 方法在取到锁前会一直阻塞,如果要监听多把锁需要在不同的协程中进行了,Unlock 一把未锁定的锁会导致 panic,虽然这情况属于逻辑错误,但是使用 channel 就可以减轻思维负担了,channel 本身提供了并发保证,好维护。
hilbertz
2019-03-27 19:14:55 +08:00
锁能提供更细的控制粒度,延迟更低,但也更复杂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/549165

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX