Go channels publish, receive and go routine scheduling

Go channels publish, receive and go routine scheduling

我有以下一段 go 脚本,我对通道读取数据和 go 例程的执行顺序有疑问。

package main

import "fmt"

func squares(c chan int) {
    fmt.Println("started squares goroutine...")
    for num := range c {
        //num := <-c
        fmt.Println(num * num)
    }
    fmt.Println("exiting squares goroutine...")
}

func main() {
    fmt.Println("main() started")
    c := make(chan int, 3)

    go squares(c)

    c <- 1
    printChannel(c)
    c <- 2
    printChannel(c)
    c <- 3
    printChannel(c)
    c <- 4
    fmt.Println("after publish 4")
    printChannel(c)
    c <- 5
    fmt.Println("after publish 5")
    printChannel(c)
    c <- 6
    printChannel(c)
    c <- 7
    printChannel(c)
    c <- 8
    printChannel(c)

    fmt.Println("main() stopped")
}

func printChannel(c chan int) {
    fmt.Println("length: ",len(c))
    fmt.Println("capacity: ",cap(c))
    
}

输出:

main() started
length:  1
capacity:  3
length:  2
capacity:  3
length:  3
capacity:  3
started squares goroutine...
1
4
9
16
after publish 4
length:  0
capacity:  3
after publish 5
length:  0
capacity:  3
length:  1
capacity:  3
length:  2
capacity:  3
length:  3
capacity:  3
main() stopped

问题:

  1. 创建的通道 ch 的容量是 3,但是直到 4 被发布到通道之前,通道不会在 squares go 例程中读取,如果容量是 3,那么 4 存储在频道

  2. 从通道中读取完所有数字后,再次将数字5发布到通道中,但通道的长度仍然为0,为什么?

Goplayground link 代码:https://play.golang.org/p/TmCcZt5n58f

无法保证 goroutine 的执行顺序,也无法保证 goroutine 何时中断(I/O,包括打印到 stdout,将是重新安排的最常见原因)。

关于你的第一个问题:你可以看到 16after publish 4 之前被打印出来了。这意味着 squares goroutine 在主 goroutine 可以开始打印信息之前从通道读取并打印正方形。当主 goroutine 尝试打印通道的长度时,4 已经消失了。

同理,发送5到channel后,squaresgoroutine已经收到了,但是还没有打印出来。它在打印之前被打断了。这意味着频道又是空的,但我们还没有看到25

如果您多次 运行 您的示例,您会看到不同的输出。有时 squares goroutine 会一直运行到 64,有时则不会。这是完全正常的。在普通代码中,你需要确保在退出之前等待数据被消费,并且你不会依赖于不同goroutines的执行顺序或时间。