Go同步和并发模型

Go synchronization and concurrency model

我是 Go 新手,我正在关注 gobyexample.com 以学习基础知识。当我到达 "closing channels" 部分时,教程会插入此代码片段(我将删除原始注释):

    package main

    import "fmt"

    func main() {
        jobs := make(chan int, 5)
        done := make(chan bool)

       go func() {
           for {
               j, more := <-jobs
               if more {
                   fmt.Println("received job", j)
               } else {
                   fmt.Println("received all jobs")
                   done <- true
                   return
               }
           }
       }()

       for j := 1; j <= 18; j++ {
           jobs <- j
           fmt.Println("sent job", j)
       }
       close(jobs)
       fmt.Println("sent all jobs")

       <-done
    }

原始代码在作业发送器循环中设置 3 而不是 18。

play.golang.org中执行这段代码是我不完全理解的。它总是输出以下内容:

sent job 1
sent job 2
sent job 3
sent job 4
sent job 5
received job 1
received job 2
received job 3
received job 4
received job 5
received job 6
sent job 6
sent job 7
sent job 8
sent job 9
sent job 10
sent job 11
sent job 12
received job 7
received job 8
received job 9
received job 10
received job 11
received job 12
received job 13
sent job 13
sent job 14
sent job 15
sent job 16
sent job 17
sent job 18
sent all jobs
received job 14
received job 15
received job 16
received job 17
received job 18
received all jobs

所以我明白 "queue" 频道(我知道这个术语不是最准确的,但为了自己学习,这是我对频道的理解)是大小为 5,所以前 10 条日志消息对我来说没问题。

但是消息 6 和 13 如何在实际发送之前先输出接收信息?如果通道大小为 5,如何连续发送 7 条消息?我错过了什么?

But how can be the message 6 and 13 be output their reception prior than their actual sending?

我们只知道 fmt.Println("received job", j)fmt.Println("sent job", j) 被打印之前被打印,这在并发工作代码中是合理的。

How can be 7 messages sent in a row, if the channel size is 5?

同样,因为我们不确切知道哪个语句先打印出来,所以这是可以预料的。队列已经可以减少了,我们还在打印。

Goroutines 运行 并发,因此它们也同时打印到标准输出(即 out-of-order)。此外,fmt.Print API 是缓冲的,因此您的打印实际上不会在调用时立即打印。这也发生在其他语言中。

这就是为什么你不能从stdout中的消息中推导出真正并发执行的goroutines。