我理解通常,如果我希望从Go例程访问范围外的变量,我有责任创建一个由Go例程在概念上拥有的副本。这对渠道也是如此,还是免除?
Effective Go #channels用“写req := req
可能看起来很奇怪,但在Go中执行此操作是合法且惯用的,”这个代码示例:
var sem = make(chan int, MaxOutstanding)
// (other code, filling sem, defining process(..), etc., omitted)
func Serve(queue chan *Request) {
for req := range queue {
<-sem
req := req // Create new instance of req for the goroutine.
go func() {
process(req)
sem <- 1
}()
}
}
我碰巧在我自己的项目中几乎复制了这个示例代码(除了我使用chan struct{}
而不是chan int
作为我的信号量,并将其声明为{{1}的本地代码} func)。盯着它,我想知道是否从多个并发goroutine访问相同的通道真的很好,或者是否需要Serve
之类的东西。
答案 0 :(得分:5)
频道访问是线程安全的,因此您无需锁定它或制作它的本地副本或类似的东西。
答案 1 :(得分:4)
是的,使用多个goroutine中的相同频道没有问题,这样做很正常。
req := req
的原因不是为了goroutine的好处,而是需要防止闭包内的意外行为。没有它,循环的每次迭代都会改变闭包内的req值,而不是每次都给它一个唯一的值。
可以在此处找到此效果的简单示例:http://play.golang.org/p/ylRQkh2SeC