Go 同步和并发模型



我是一个新的围棋学习者,我正在按照 gobyexample.com 学习基础知识。当我到达"关闭通道"部分时,教程会插入以下代码片段(我将删除原始注释(:

    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
所以我知道频道

的"队列"(我知道这个术语不是最准确的,但为了学习我自己,这是我对频道的理解(的大小为 5,所以前 10 条日志消息对我来说很好。

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

Goroutines 并发运行,因此它们也会同时打印到 stdout(即乱序(。此外,FMT。打印 API 是缓冲的,因此打印在调用时实际上不会立即启动。这在其他语言中也会发生。

这就是为什么您无法从 stdout 中的消息中导出 goroutines 的真正并发执行。

但是,如何在消息 6 和 13 的实际发送之前输出它们的接收?

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

如果通道大小为 7,如何连续发送 5 条消息?

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

最新更新