golang 中很容易开启多个协程,那开启的这么多协程如何保证在 main 函数结束前这些协程都是安全退出呢(信道都安全关闭),这里我们使用到了 select,close 关闭信道函数以及 sync.WaitGroup 函数
前置知识当信道被 close 掉之后,如果信道中有缓存,那么被关闭后是不能写的但是依然可以读取缓存数据,缓存被读完后读到的就是 0;如果信道中没有缓存,那么信道被关闭后直接读到的就是 0
多协程安全退出粗糙版func worker(channel chan bool) {
for {
select {
default:
fmt.Println("hello world!")
case <-channel:
return
}
}
}
func main() {
channel := make(chan bool)
for i := 0; i < 10; i++ {
go worker(channel)
}
time.Sleep(time.Second)
close(channel)
}
为什么说这个是粗糙版呢?因为当 main 中的 close 函数执行关闭信道后,在极短时间内,可能会有一部分协程完成了
case <-channel:
return
但是有可能并不是所有的协程都执行完 return 结束协程,可能还存在一些协程没有被彻底执行结束然后 main 函数就直接关闭了
多协程安全退出完美版func worker(wg *sync.WaitGroup, channel chan bool) {
defer wg.Done()
for {
select {
default:
fmt.Println("hello world!")
case <- channel:
return
}
}
}
func main() {
channel := make(chan bool)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(&wg, channel)
}
time.Sleep(time.Second)
close(channel)
wg.Wait()
}
当我们使用了 sync.WaitGroup 函数就可以保证当所有协程都完成了 wg.Done 即所有协程都被关闭后 wg.Wait 才会被放行
也就是说当信道被 close 后,会被卡在 wg.Wait,wg.Wait 函数会等到所有协程的 wg.Done 都被执行后(所有协程都被关闭后)才会放行 wg.Wait,这样也就完美解决了使用 select 和 close 当主协程 main 关闭前让所有的协程都安全的退出的问题
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)