假如有一个方法一直在打印提示信息,现在想要在main方法中经过一段的时间主动的去停止,这个时候我们可以选择使用共享变量的方式(注意加读写锁),也可以使用channel的方式。例如:
共享变量:
var stop bool
var rwlock sync.RWMutex
var wg sync.WaitGroup
func g1() {
for {
rwlock.RLock()
if stop {
fmt.Println("退出了捏")
wg.Done()
return
}
time.Sleep(time.Second)
fmt.Println("欸嘿!")
rwlock.RUnlock()
}
}
func main() {
wg.Add(1)
go g1()
time.Sleep(3*time.Second)
rwlock.Lock()
stop = true
rwlock.Unlock()
wg.Wait()
fmt.Println("退出程序")
}
运行结果:
欸嘿!
欸嘿!
欸嘿!
退出了捏
退出程序
使用channel:
var wg sync.WaitGroup
func g1(stop chan struct{}) {
for {
select {
case <- stop:
fmt.Println("退出了捏")
wg.Done()
return
default:
time.Sleep(time.Second)
fmt.Println("欸嘿!")
}
}
}
func main() {
stop := make(chan struct{})
wg.Add(1)
go g1(stop)
time.Sleep(3*time.Second)
stop <- struct{}{}
wg.Wait()
fmt.Println("退出程序")
}
因为channel是协程安全的所以不用加锁
运行结果:
欸嘿!
欸嘿!
欸嘿!
退出了捏
退出程序
除此之外,还有一种更常用的方式,就是使用context,例如:
var wg sync.WaitGroup
func g1(ctx context.Context) {
for {
select {
case <- ctx.Done():
fmt.Println("退出了捏")
wg.Done()
return
default:
time.Sleep(time.Second)
fmt.Println("欸嘿!")
}
}
}
func main() {
wg.Add(1)
ctx, cancel := context.WithCancel(context.Background())
go g1(ctx)
time.Sleep(3*time.Second)
cancel()
wg.Wait()
fmt.Println("退出程序")
}
运行结果:
欸嘿!
欸嘿!
欸嘿!
退出了捏
退出程序
WithCancel() 方法返回值是一个 context.Context 类型的interface和一个cancel方法
ctx(context.Context)有一个Done方法,返回值是一个channel
当使用cancel方法之后,ctx会向Done()返回的channel中发送一个信号
此时接受到信号,select跳转到退出的分支,由此完成对goroutine的信息传递实现主动退出