Golang中通道容量问题的探讨

Golang中通道容量问题的探讨

  1. 当尝试向通道写入第 N+2 个或第 N+1 个值时,此程序是否会被阻塞?考虑到输出结果,可能会认为阻塞发生在第 N+2 次写入时,但我们知道理论上应该是在第 N+1 次写入时发生阻塞。那么实际情况究竟是怎样的呢?
  2. 如果我们将输出 “generator finish” 的那行代码放在 close(out) 之后,那么程序的输出将不总是包含 “generator finish” 这一行 - 这是为什么?
package main

import (
	"fmt"
)

func main() {
	in := make(chan int, 1)
	go func(out chan<- int) {
		for i := 0; i < 3; i++ {
			fmt.Println("before", i)
			out <- i
			fmt.Println("after", i)
		}
		fmt.Println("generator finish")
		close(out)
	}(in)
	for i := range in {
		fmt.Println("_____get", i)
	}
}

before 0 after 0 before 1 after 1 before 2 _____get 0 _____get 1 _____get 2 after 2 generator finish


更多关于Golang中通道容量问题的探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

两篇帖子已合并至现有主题:Channel capacity definition

更多关于Golang中通道容量问题的探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在 Go 语言中,通道的容量决定了它可以缓冲的元素数量。对于容量为 N 的缓冲通道,当通道已满(即已有 N 个元素)时,尝试写入第 N+1 个值会阻塞,直到有空间可用。在您的代码中,通道 in 的容量为 1,因此:

  1. 阻塞行为分析:当通道已有一个元素时,尝试写入第二个值(即第 N+1 次写入)会阻塞。在您的示例中,输出显示 “before 0” 后立即写入 0(通道为空,不阻塞),然后输出 “after 0”。接着 “before 1” 后尝试写入 1,但此时通道已满(有值 0),因此写入阻塞,直到主协程从通道读取值 0(输出 “_____get 0”),之后写入 1 完成,输出 “after 1”。类似地,写入 2 时也可能阻塞,取决于时机。理论上,阻塞发生在第 N+1 次写入(即第二次写入),但实际输出顺序受调度影响。例如,在您的输出中,写入 1 后没有立即阻塞,因为主协程及时读取了值。

  2. "generator finish" 输出问题:如果将 fmt.Println("generator finish") 放在 close(out) 之后,由于 close 操作不会阻塞,但主协程在 range in 循环中一旦通道关闭就会退出,这可能导致生成器协程中的 fmt.Println("generator finish") 未执行或输出被截断,尤其是在程序退出时。如果主协程先退出,整个程序终止,生成器协程可能来不及输出。例如:

// 修改后的代码示例:将输出放在 close 之后
go func(out chan<- int) {
    for i := 0; i < 3; i++ {
        fmt.Println("before", i)
        out <- i
        fmt.Println("after", i)
    }
    close(out)
    fmt.Println("generator finish") // 这行可能不会输出
}(in)

在快速执行环境中,主协程在通道关闭后立即结束循环并退出程序,可能中断生成器协程的输出。要确保输出,可添加同步机制,如使用 sync.WaitGroup,但根据问题,不扩展建议。总之,输出不总是包含 “generator finish” 是因为程序退出时机不确定,导致协程未完成输出。

回到顶部