我尝试使用Go频道并与go blog下面的功能示例混淆:
func gen(nums []int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
fmt.Println("return statement is called ")
return out
}
主要:
func main() {
c := make(<-chan int)
c = gen([]int{2, 3, 4, 5})
// Consume the output.//Print 2,3,4,5
fmt.Println(<-c)
fmt.Println(<-c)
fmt.Println(<-c)
fmt.Println(<-c)
}
完整代码:http://play.golang.org/p/Qh30wzo4m0
我的怀疑:
我的理解是,一旦return
被调用,函数将被终止,并且该函数内的通道不再有生命。
return
语句只调用一次。但是out
频道的内容被多次阅读。在这种情况下,实际的执行流程是什么?
(我是并发编程的新手。)
答案 0 :(得分:9)
out := make(chan int)
这不是缓冲频道,这意味着out <- n
将阻止,直到有人在某处读取该频道(fmt.Println(<-c)
来电)
(另见“do golang channels maintain order”)
因此,gen()
函数末尾的返回并不意味着文字go func()
已终止(因为它仍在等待读者使用out
频道的内容)。
但
main
功能从out
功能返回gen()
频道gen()
终止后如何才能获得它?
gen()
终止的事实对其返回值(out
频道)没有影响:“gen()
”的目标是“生成”out
信道。
main
可以在out
终止后很长时间内使用gen()
(作为gen()
的返回值)。
go func
内的文字gen()
仍在运行,即使gen()
已终止。
答案 1 :(得分:1)
因为gen()
会像goroutine一样触发频道填充功能;
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
并且当out
通道上发送第一个值时它会阻塞,因为尚未接收任何内容(无缓冲通道阻止发送直到收到它们的内容),goroutine 不会在gen()
函数返回。
来自c
main()
的收到
fmt.Println(<-c)
...
然后导致在gen()
中启动的goroutine在结果被读出时继续填充通道,然后当goroutine返回时最终返回main()
,因为没有任何内容可以发送out
1}},并且c
无法接收任何内容。
此外,c := make(<-chan int)
中的main()
是不必要的,因为gen()
会创建一个频道并将其返回。
请参阅Playground
答案 2 :(得分:-1)
我认为这就是您想要的:https://play.golang.org/p/WSBUPPyQiY6
package main
import (
"fmt"
"sync"
"time"
)
func read() (elemChan chan int) {
elemChan = make(chan int)
go func() {
for k := 0; k < 1000; k++ {
elemChan <- k
}
close(elemChan)
}()
return
}
func main() {
fmt.Println("Hello, playground")
elemChan := read()
wg := sync.WaitGroup{}
for k := 0; k < 2; k++ {
wg.Add(1)
go func(k int) {
for {
e, more := <-elemChan
if !more {
wg.Done()
return
}
fmt.Printf("goroutine #%d: %d\n", k, e)
time.Sleep(1000 * time.Nanosecond)
}
}(k)
}
wg.Wait()
}