这是Golang的示例代码之一。但在这种情况下无法理解为什么“完成”频道需要。
https://gobyexample.com/closing-channels
没有理由将真实发送到完成频道。当打印“发送所有工作”消息时,我们可以知道工作通道已完成,不是吗?
我删除了相对于完成频道的代码,结果仍然相同。
答案 0 :(得分:4)
TL; DR:有竞争条件---你很幸运。
如果您没有done
频道,则该节目的输出是不确定的。
根据线程执行顺序,主线程可能会在goroutine完成处理之前退出,从而导致goroutine在中途被杀死。
通过强制主线程从done
频道读取,我们强制主线程等待,直到done
频道中有一些数据被消耗。这给了我们一个简洁的同步机制,其中goroutine通过写入done
通道通知主线程它已完成。这反过来导致主线程阻塞<- done
完成并导致程序终止。
答案 1 :(得分:4)
结果不一样:
在许多情况下,你的主要goroutine退出received job
goroutine(例如,不同的CPU负载,并且它是不确定的和系统相关的行为),因此你不能保证all jobs received
,例如只需添加
time.Sleep(500)
前
fmt.Println("received job", j)
要查看此内容,请在The Go Playground上尝试:
// _Closing_ a channel indicates that no more values
// will be sent on it. This can be useful to communicate
// completion to the channel's receivers.
package main
import (
"fmt"
"time"
)
// In this example we'll use a `jobs` channel to
// communicate work to be done from the `main()` goroutine
// to a worker goroutine. When we have no more jobs for
// the worker we'll `close` the `jobs` channel.
func main() {
jobs := make(chan int, 5)
//done := make(chan bool)
// Here's the worker goroutine. It repeatedly receives
// from `jobs` with `j, more := <-jobs`. In this
// special 2-value form of receive, the `more` value
// will be `false` if `jobs` has been `close`d and all
// values in the channel have already been received.
// We use this to notify on `done` when we've worked
// all our jobs.
go func() {
for {
j, more := <-jobs
if more {
time.Sleep(500)
fmt.Println("received job", j)
} else {
fmt.Println("received all jobs")
//done <- true
return
}
}
}()
// This sends 3 jobs to the worker over the `jobs`
// channel, then closes it.
for j := 1; j <= 3; j++ {
jobs <- j
fmt.Println("sent job", j)
}
close(jobs)
fmt.Println("sent all jobs")
// We await the worker using the
// [synchronization](channel-synchronization) approach
// we saw earlier.
//<-done
}
输出:
sent job 1
sent job 2
sent job 3
sent all jobs
而不是:
sent job 1
received job 1
received job 2
sent job 2
sent job 3
received job 3
received all jobs
sent all jobs
请参阅:
Goroutine does not execute if time.Sleep included
Why is time.sleep required to run certain goroutines?
Weird channel behavior in go
答案 2 :(得分:1)
当工作需要很长时间时,发送并不意味着工作已经完成 完。
作业通道被缓冲,因此即使发送作业,作业也可以 工作人员甚至没有收到。
答案 3 :(得分:0)
我认为接受的答案,没有说明原因。
基本的想法就是这样,记住golang是一种先行语言,这意味着每个指令都是线性执行的,请记住,当Goroutine从主要的goroutine分叉时,它基本上就是在自己的小冒险中消失。离开主线程返回。缓冲通道的容量为5,这意味着它在缓冲区已满之前不会阻塞,并且如果其为空则将阻塞(注意容量为零的通道自然是无缓冲的)。因为它只有4次迭代(0到&lt; = 3)它不会阻塞。理解这一行,通过强制主线程从完成通道读取,我们迫使主线程等待,直到完成通道中有一些数据被消耗。因此,当迭代结束时,执行else块,然后
done <- true
使阻塞线程<- done
从done
拉出现在插入的值。主要的Goroutine不再被阻挡,因此终止成功。