``` go
package main
import (
"fmt"
)
func producer(nums ...int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for _, n := range nums {
out <- n
}
}()
return out
}
func square(inCh <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range inCh {
out <- n * n
}
}()
return out
}
func main() {
in := producer(1, 2, 3, 4)
ch := square(in)
for ret := range ch {
fmt.Printf("%3d", ret)
}
}
```
这个是go代码,可以直接执行,结果是1 4 9 16 。 也在goland里面单步跟踪了,但是还是不理解执行原理。就像问一下,这个执行过程。producer 和square 里面不是go协程吗? 还是无缓冲的,这个不应该阻塞吗?再次,如果返回了return out ,这两个函数应该结束了,我单步跟踪发现,从main里面又跳入到producer 和square 这两个函数里面执行。这个和之前接触的协程上理解不了。求大神指点一二。
这段代码中起了三个协程:主协程main,producer,square,创建了两个无缓冲的channel,这三个协程通过两个channel串联起来组成了一个pipeline。
![DeepinScreenshot_select-area_20190116154131.png](https://static.studygolang.com/190116/e3b057c582fa3cc527fc865b36e65060.png)
从问题描述中看有几个关键点需要理解的:
- channel 是引用类型(感觉你忽略了这点)
- 无缓冲的 channel 读和写都是阻塞的
- for-range channel 会阻塞直到channel被关闭
大致流程:
producer 中创建了一个无缓冲的 channel 叫做 out,并把这个channel作为返回值,同时起了一个协程向这个channel中写入1,2,3,4,最终关闭这个channel,协程退出。
producer 返回的 channel,作为入参,传递给了 square 换了个名字叫做 inCh。
square 中也创建了一个 channel 叫做 out,起了一个协程,从 inCh 中阻塞读数据,同时向 out 中阻塞写数据,写入 1, 4, 9, 16,最终关闭这个 channel,协程退出,并把 out 作为返回值返回。
main 中 for-range 从 square 中返回的 channel,直到这个 channel 关闭,主协程退出。
#5
更多评论
<a href="/user/songlq" title="@songlq">@songlq</a> 如果没有值一直等待那样就出现死锁了,这个代码是可以正常执行的。不理解的地方就是在协程里面return 这个<-chan int ,然后执行代码又跳到已经return的函数里面去执行。
#2