【发布时间】:2020-04-23 09:58:13
【问题描述】:
我是 golang 新手,很难理解渠道的工作原理。我的理解是,默认情况下,通道应该是阻塞的,所以我希望一个写入通道的 goroutine 被调度程序冻结,直到另一个 goroutine 读取通道内容。所以我尝试了以下代码,它给出了相应的输出:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var v int
func main() {
ch := make(chan string)
wg.Add(2)
go func(ch chan string) {
fmt.Println("Ready to receive")
for msg := range ch {
fmt.Println("received: ", msg)
fmt.Println(v)
}
wg.Done()
}(ch)
go func(ch chan string) {
fmt.Println("Will send the SMS to mama")
ch <- "msg 1"
v += 1
fmt.Println("Done! sent the message 1")
ch <- "msg 2"
v += 1
fmt.Println("Done! sent the message 2")
ch <- "msg 3"
v += 1
fmt.Println("Done! sent the message 3")
close(ch)
wg.Done()
}(ch)
wg.Wait()
}
输出:
Will send the SMS to mama
Ready to receive
received: msg 1
0
Done! sent the message 1
Done! sent the message 2
received: msg 2
2
received: msg 3
2
Done! sent the message 3
我有点惊讶,因为我期待以下顺序:
- 消息 1 已发送
- 收到消息 1
- 消息 2 已发送
- 收到消息 2
等等。但显然情况并非如此。
有人知道为什么 Go 会这样吗?非常感谢,
这里是代码https://play.golang.org/p/O6SXf0CslPf 的链接。以下是我之前所说的话的来源:https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adbhttps://rakyll.org/scheduler/
【问题讨论】:
-
在通道上发送/接收只能保证发送和接收是同步的。不保证后续打印操作的时间。
-
v上存在数据竞争。您可以期望发送操作之前的打印语句发生在接收操作之后的打印语句之前,确实如此。 -
谢谢大家的回答。 @CeriseLimón这是否意味着我们只能保证发送发生在接收操作之前?难道我们不能保证调度程序会在它读取此语句的确切时刻切换到接收者 goroutine,例如
ch <- "msg 1"? -
@A.Luc 除非进一步同步,否则任何 goroutine 都可以在无缓冲通道同步后继续(可能同时并行超过 1 个)。
-
@A.Luc 以下是来自memory model 的相关引用:通道上的发送发生在该通道的相应接收完成之前。 没有其他保证关于在通道操作上调度 goroutines。