在编写代码过程中如果使用了协程,通常在主程序中使用wg.Wait()等待所有协程处理结束后才能执行主程序的退出
例如
package main
import (
"fmt"
"sync"
"time"
)
var wg1 sync.WaitGroup
func f1(){
time.Sleep(time.Second*5)
fmt.Println("aaaaa")
wg1.Done()
}
func main(){
wg1.Add(1)
go f1()
wg1.Wait()
fmt.Println("quit success")
}
当fi等待5s后执行wg1.Done(),此时主函数中wg1.Wait()进入非阻塞,函数退出。
但是,当主程序非正常退出时,fi协程就不会优雅的退出
如何优雅的退出?
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
)
var wg sync.WaitGroup
var in=make(chan int,1)
var quit=make(chan int,1)
var quito0k=make(chan int,1)
func ListenQuit(){
defer wg.Done()
var sign=make(chan os.Signal,1)
signal.Notify(sign,syscall.SIGINT)
<-sign
SQuit()
}
func run(){
defer wg.Done()
Quit:
for {
select {
case out := <-in:
fmt.Println(out)
case <-quit:
break Quit
}
}
}
func producerin(){
Quit:
for {
select {
case in<-0:
case <-quit:
break Quit
}
}
}
func SQuit(){
close(quit)
go func(){
wg.Wait()
quito0k<-0
}()
}
func main(){
go ListenQuit()
go func(){
for i := 0; i <10; i++ {
wg.Add(1)
go run()
}
}()
wg.Add(1)
go producerin()
<-quito0k
fmt.Println("qiut ok")
}
首先在最开始创建一个监听协程go ListenQuit(),当没有退出信号时,该协程会一直阻塞,
signal.Notify(sign,syscall.SIGINT)
<-sign
创建一个生产协程和n个消费协程
go func(){
for i := 0; i <10; i++ {
wg.Add(1)
go run()
}
...
go producerin()
两个协程会一直循环生产处理in通道中的消息
当监听退出的协程,监听到信号后,会进入非阻塞状态,执行SQuit()、close(quit),从而使producerin和run协程中的循环停止(随机选取case总会处理case <-quit:)
func run(){
defer wg.Done()
Quit:
for {
select {
case out := <-in:
fmt.Println(out)
case <-quit:
break Quit
}
}
}
参照:
https://blog.csdn.net/qq_34673519/article/details/100109640
https://blog.csdn.net/qq_34673519/article/details/100110194
go func(){
wg.Wait()
quito0k<-0
}()
...
<-quito0k
当所有协程均正常退出后,main进入非阻塞,退出。