Go channels 似乎没有阻塞,尽管应该是

Go channels seem not to be blocking although supposed to be

我是 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. 收到消息 1
  3. 第 2 条消息已发送
  4. 收到消息 2

等等。但事实显然并非如此。

有人知道为什么 Go 会这样吗?非常感谢,

这里是 link 代码 https://play.golang.org/p/O6SXf0CslPf. And here are my sources for stating what I said earlier: https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb https://rakyll.org/scheduler/

这种行为是完全正常的,所以回答你的问题

so I expect a goroutine that writes into a channel to be frozen by the scheduler until an other goroutine reads the channel content

除非需要进一步同步,否则在通过通道发送值后,调度可能会也可能不会继续同一个 goroutine。

所以例如 "msg 2" 发送到 ch 并在下一行中的另一个 goroutine 中读取

ch <- "msg 2"

goroutine 可以继续执行 v += 1 并在其他 goroutine 调用它之前调用 fmt.Println

从不同的 goroutines 调用 fmt.Println 也需要同步,并且可能 mutex 调用也可能重新排序打印语句。

此外还有变量 v

的数据竞争