UnBuffered Channel 不以同步方式工作

UnBuffered Channel not working in synchronous way

我对 GoLang 世界还很陌生,正在尝试 goroutines/channels。 据我了解,通道是 goroutine 之间的双向通信方式。 如果我们创建一个长度为 0 的通道,它应该是一个同步通道,这意味着除非某个 goroutine(即消费者)从通道读取值,否则生产者将无法继续前进。

我尝试了下面的例子来测试这个,但我没有得到预期的结果。

package main

import (
    "fmt"
    "time"
)

var done = make(chan bool)
var msgs = make(chan int)

func produce() {
    for i := 0; i < 40; i++ {
        //fmt.Println("sending")
        fmt.Println("Produced: ", i)
        msgs <- i
        //fmt.Println("Channel size is: ", len(msgs))
    }
    fmt.Println("Before closing channel")
    close(msgs)
    fmt.Println("Before passing true to done")
    

}

func consume() {
    for msg := range msgs {
        //fmt.Println("Going to take one, Channel size is: ", len(msgs))
        fmt.Println("Consumer: ", msg)
        time.Sleep(100 * time.Millisecond)

    }
    done <- true
    
}

func main() {
    go produce()
    go consume()
    <-done
    fmt.Println("After calling DONE")
}

输出:

Produced:  0
Produced:  1
Consumer:  0
Consumer:  1
Produced:  2
Consumer:  2
...

我期望输出是

Produced:  0
Consumer:  0
Produced:  1
Consumer:  1
Produced:  2
Consumer:  2

请帮我指出我做错了什么?

(无缓冲)通道 reads/writes 将按您期望的顺序出现:一次写入;一读;一写;一读等等

然而,producer/consumer goroutines 中的 fmt.Println 调用是 同步的——因此生产者可能会得到它的 fmt.Printlnconsumer.

之前进入调度程序

并且由于 consumer 睡眠 - 它自愿向调度程序发出提示,让其他 goroutines 运行 领先于它。所以 producer 很可能总是在 consumer 醒来之前得到它的第二个 fmt.Println 运行。

如果将 sleep 移动到 producer goroutine,您可以在操场上看到预期的行为:https://play.golang.org/p/5x9_yyUaMiJ - 但是您不应该依赖这些计时技巧。如果你想确保一个函数相对于另一个 goroutine 的执行顺序,那些任务也必须同步。使用通道 reads/writes - 只有 reads/writes 保证 goroutine 安全且按顺序。