【问题标题】:Can Go routines share ownership of a channel?Go 例程可以共享频道的所有权吗?
【发布时间】:2014-06-27 16:30:57
【问题描述】:

我知道,通常,如果我希望从 Go 例程访问范围外的变量,我有责任创建一个副本以在概念上由 Go 例程拥有。频道也是如此,还是那些被豁免的?

Effective Go #channels 用“写req := req 可能看起来很奇怪,但在 Go 中这样做是 [sic] 合法且惯用的”字样解释了这一点,参考以下代码示例:

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 作为我的信号量,并将它声明为Serve 函数的本地)。盯着它看,我想知道从多个并发 goroutine 访问同一个通道是否真的很好,或者是否需要 sem := sem 之类的东西。

【问题讨论】:

标签: concurrency go race-condition channel goroutine


【解决方案1】:

是的,从多个 goroutine 使用同一个通道没有问题,这样做很正常。

req := req 的原因不是为了 goroutine 的利益,而是为了防止闭包中出现意外行为。没有它,循环的每次迭代都会改变闭包内 req 的值,而不是每次都给它一个唯一的值。

可以在此处找到此效果的简单示例:http://play.golang.org/p/ylRQkh2SeC

【讨论】:

  • 感谢您抽出宝贵时间回答我的问题!但是:无论chan 的当前或未来实现在内部做什么,都可能会担心您为req 提到的这种竞争条件(“意外行为”)。如果您回答了我的问题,则取决于对“同一频道”的解释,我认为在这种情况下这是模棱两可的。举例说明:如果我将通道作为函数参数传递给闭包,它仍然是同一个通道吗?如果是,你还没有回答我的问题;如果不是,那是什么频道?
  • 通道只是一个值。您可以随心所欲地传递该值。它将始终引用可以被任何可以访问它的 goroutine 读取或写入的相同通道。这通常是你应该在 goroutine 之间共享通道的方式,因为如果多个 goroutine 正在使用它,更改包含通道值的变量可能会导致它自己的竞争条件。
  • 金字塔,值得强调的是,Innominate 的意外行为与闭包有关,而不是 goroutines。即使 GOMAXPROCS=1,所有函数都将查看相同的 req 变量,就好像它是一个全局变量一样。但是如果你运行req := req 来定义一个新的变量,每个循环都通过,每个闭包都有自己的req 变量,一切都很好。如果有帮助,可以在play.golang.org/p/aW_C7Xwub6 进行没有go 语句的演示。
  • 我知道,@twotwotwo。不过,这不是我的问题。
【解决方案2】:

通道访问是线程安全的,因此您不需要锁定它或制作它的本地副本或类似的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 2011-01-16
    • 2018-02-18
    • 2012-02-11
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多