用channel控制goroutine的退出
本文简要介绍了,如何用channel控制goroutine的退出的基本方法
for-range主动停止goruitine
package main
import (
"fmt"
"sync"
"time"
)
/*
Go并发编程模型:主动停止goroutine
方法一:for-rang从channel上接收值,直到channel关闭
*/
var wg sync.WaitGroup
func work(ch chan int) {
defer wg.Done()
// for range关键字,将其使用在channel上时,会自动等待channel的动作一直到channel被关闭close
// 也就是clase(sh)后,for range就会退出
for i := range ch {
fmt.Println(i)
}
fmt.Println("work exit")
}
func main() {
wg.Add(1)
var ch chan int
ch = make(chan int)
go work(ch)
for i := 0; i < 3; i++ {
time.Sleep(1 * time.Second)
ch <- i
}
time.Sleep(3 * time.Second)
for i := 4; i < 7; i++ {
time.Sleep(1 * time.Second)
ch <- i
}
// close(sh)来控制"work"协程中的for range的完成
close(ch)
wg.Wait()
}
后台定时任务
// 设定一个定时器,当定时器触发是就执行一次任务
tricker := time.NewTicker(1 * time.Second)
defer fmt.Println("tricker.Stop()")
defer tricker.Stop()
for {
select {
case <-stopCh:
fmt.Println("do1 exit.")
return
//心跳,心跳一次就执行一次任务
case <-tricker.C:
time.Sleep(1 * time.Second)
fmt.Println("do1 doing....")
}
}
使用stopCh控制goroutine退出
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func do1(stopCh chan struct{}) {
defer wg.Done()
for {
select {
case <-stopCh:
fmt.Println("go1 exit.")
return
default:
time.Sleep(1 * time.Second)
fmt.Println("go1 doing....")
}
}
}
func do2(stopCh chan struct{}) {
defer wg.Done()
for {
select {
case <-stopCh:
fmt.Println("go2 exit.")
return
default:
time.Sleep(1 * time.Second)
fmt.Println("go2 doing....")
}
}
}
func main() {
wg.Add(2)
stopCh := make(chan struct{})
go do1(stopCh)
go do2(stopCh)
time.Sleep(5 * time.Second)
// 让一个goroutine退出
stopCh <- struct{}{}
time.Sleep(5 * time.Second)
// 让另一个goroutine退出
stopCh <- struct{}{}
wg.Wait()
}
关闭channel来控制goroutine退出
package main
import (
"fmt"
"sync"
"time"
)
/*
多个通道都关闭才退出
利用select的一个特性,select不会在nil的通道上进行等待
*/
var wg sync.WaitGroup
func work(in, exit1, exit2 chan bool) {
defer wg.Done()
for {
select {
// 当exit管道收到信号后退出goroutine
case v := <-exit1:
fmt.Println("exit1 收到退出信号")
fmt.Println("v=", v)
exit1 = nil
case <-exit2:
fmt.Println("exit2 收到退出信号")
exit2 = nil
case value := <-in:
fmt.Println(value)
}
fmt.Println(time.Now())
fmt.Println("遍历了一次")
// 当2个退出通道都收到信号时,就退出for循环
if exit1 == nil && exit2 == nil {
return
}
}
}
func main() {
in := make(chan bool)
exit1 := make(chan bool)
exit2 := make(chan bool)
wg.Add(1)
go work(in, exit1, exit2)
for i := 0; i < 6; i++ {
time.Sleep(5 * time.Millisecond)
in <- true
}
// 主动停止goroutine方法一
//exit1 <- 1
//exit2 <- 1
// 主动停止goroutine方法二
close(exit1)
close(exit2)
wg.Wait()
}