关于Go函数内Goroutine跨作用域执行的技术疑问
Go管道中多个goroutine共享通道的行为解析
先看你提到的核心代码片段:
// 将数字传入通道 func gen(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out } // 对从"in"通道接收的数字求平方 func sq(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { out <- n * n } close(out) }() return out } func main() { in := gen(2, 3) // 将sq的工作分配给两个均从in读取的goroutine c1 := sq(in) c2 := sq(in) }
为什么c1和c2都能拿到值?
sq不是普通的同步函数:它执行时会立刻启动一个goroutine,然后直接返回out通道,不会等待内部goroutine处理完所有值。当你连续调用两次sq(in)时,相当于启动了两个独立的goroutine,它们都会监听同一个in通道。
对于无缓冲通道(gen创建的就是无缓冲通道),发送和接收是同步的:gen的goroutine发送2时,会阻塞直到有某个sq的goroutine准备好接收;此时两个sq的goroutine都在等待接收in的值,它们会竞争获取通道中的元素——哪个goroutine先被调度到,就会拿到当前的数值,处理后发送到自己的out通道。发送3时同理,剩下的那个goroutine会拿到这个值。
所以最终c1和c2会各自拿到一个平方值(顺序不确定,取决于Go调度器),而不是一个取完所有值、另一个为空。
关于goroutine的作用域误解
函数内部启动的goroutine不会“跳出函数作用域回到主协程”。goroutine是Go运行时管理的独立执行单元,一旦启动就会和主协程(或其他goroutine)并发运行,和启动它的函数是否执行完毕无关。sq函数执行完返回通道后,它内部的goroutine依然会在后台运行,直到in通道关闭并处理完所有接收的值。
内容的提问来源于stack exchange,提问作者iwa2no
相关产品推荐
相关产品推荐

