英文:
Can Go routines share ownership of a channel?
问题
我理解通常情况下,如果我希望从Go协程中访问一个超出作用域的变量,那么我有责任创建一个副本,以便概念上由Go协程拥有。对于通道是否也适用这一规则呢?
Effective Go #channels 用这样的话解释了这个问题:“写req := req
可能看起来很奇怪,但在Go语言中这是合法且惯用的”,并提到了以下代码示例:
var sem = make(chan int, MaxOutstanding)
// (其他代码,填充sem,定义process(..)等,被省略)
func Serve(queue chan *Request) {
for req := range queue {
<-sem
req := req // 为协程创建req的新实例。
go func() {
process(req)
sem <- 1
}()
}
}
我碰巧在自己的项目中几乎复制了这个示例代码(除了我使用chan struct{}
而不是chan int
作为信号量,并将其声明为Serve
函数的局部变量)。仔细观察后,我想知道是否可以从多个并发的Go协程中访问同一个通道,或者是否需要像sem := sem
这样的操作。
英文:
I understand that usually, if I wish to access an out-of-scope variable from a Go routine, it is my responsibility to create a copy to be conceptually owned by the Go routine. Is this also true for channels, or are those exempt?
Effective Go #channels explains this with the words "it may seem odd to write req := req
but it's a [sic] legal and idiomatic in Go to do this," referring to this code example:
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
}()
}
}
I happened to have very nearly replicated this example code in my own project (except that I am using a chan struct{}
rather than chan int
for my semaphore, and declare it local to the Serve
func). Staring at it, I am wondering if accessing the same channel from multiple concurrent goroutines is really fine, or if something like sem := sem
is called for.
答案1
得分: 5
是的,使用多个goroutine从同一个通道接收数据没有问题,这是很正常的做法。
req := req
的目的不是为了goroutine的好处,而是为了防止闭包中出现意外行为而必需的。如果没有它,循环的每次迭代都会改变闭包中的req的值,而不是为其赋予每次迭代一个唯一的值。
可以在这里找到一个快速示例:http://play.golang.org/p/ylRQkh2SeC
英文:
Yes, there is no issue with using the same channel from multiple goroutines, it's quite normal to do so.
The reason for the req := req
is not for the benefit of the goroutine, but is instead required to prevent unexpected behavior within the closure. Without it, each iteration of the loop will change the value of req within the closure rather than giving it a unique value each time.
A quick example of this effect can be found here: http://play.golang.org/p/ylRQkh2SeC
答案2
得分: 4
通道访问是线程安全的,因此您不需要对其进行锁定、制作本地副本或其他任何操作。
英文:
Channel accesses are thread-safe, so you do not need to lock it or make local copies of it or anything like that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论