0%

golang优雅的等待或通知goroutine退出

1. 等待 goroutine 退出

1.1 使用Waitgroup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main

import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)

type Service struct {
ch chan bool
waitGroup *sync.WaitGroup
}

func NewService() *Service {
s := &Service{
ch: make(chan bool),
waitGroup: &sync.WaitGroup{},
}

return s
}

func (s *Service) Stop() {
close(s.ch) // 3. 发送golang内部关闭信号
s.waitGroup.Wait()
fmt.Println("彻底over,彻底退出") // 4. 服务真正退出
}

func (s *Service) Serve() {
fmt.Println("Server start")
s.waitGroup.Add(1)
defer s.waitGroup.Done()
index := 1
for {
select {
case <-s.ch:
fmt.Println("Server stopping...")
return
default:
time.Sleep(time.Second) // 每秒开一个go
s.waitGroup.Add(1)
go s.anotherServer(index)
index++
}
}
}

func (s *Service) anotherServer(index int) {
fmt.Println("anotherServer start", index)
defer s.waitGroup.Done()
for {
select {
case <-s.ch:
fmt.Println("anotherServer stopping...", index)
return
default:
}
}
}

func main() {
service := NewService()
go service.Serve()

ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) // 1. 卡在这里
fmt.Println("收到退出了到信号", <-ch)

service.Stop() // 2. 收到系统信号,处理清理逻辑
}

/*
Server start
anotherServer start 1
anotherServer start 2
anotherServer start 3
anotherServer start 4
^C收到退出了到信号 interrupt
anotherServer stopping... 4
anotherServer stopping... 2
anotherServer stopping... 1
anotherServer stopping... 3
Server stopping...
anotherServer start 5
anotherServer stopping... 5
彻底over,彻底退出
*/
  1. close无缓冲的channle,有广播效果。
  2. wait 所有go 退出。

1.2 怎么知道go活干完了呢?

还是用 waitgroup 等待。

2. 通知 goroutine 退出

2.1 close channel广播

用关闭一个channel来进行广播。

2.2 使用ctx的cancel

可以加首页作者微信,咨询相关问题!