golang 中四种结束子协程的方法
在 golang 中,怎样更好的控制子协程的退出呢,这里说说可用的几种方法:
- channel
- context
- sync.WaitGroup
- runtime.GoExit()
具体见测试代码:
package main
import (
"context"
"log"
"math"
"math/rand"
"runtime"
"sync"
"testing"
"time"
)
func TestChanClose(t *testing.T) {
ch := make(chan struct{})
go func() {
for {
select {
case <- ch:
log.Println("Channel closed, and now exit.")
return
default:
log.Println("Exec task...")
time.Sleep(500 * time.Millisecond)
}
}
}()
log.Println("Main thread handle...")
time.Sleep(3 * time.Second)
ch <- struct{}{}
log.Println("Main thread done!")
}
func TestCtxTimeout(t *testing.T) {
ctx := context.Background()
ctx, _ = context.WithTimeout(ctx, 3*time.Second)
go func() {
for {
select {
case <- ctx.Done():
log.Println("Recv ctx timeout signal, exit.")
return
default:
log.Println("Exec task...")
time.Sleep(500 * time.Millisecond)
}
}
}()
log.Println("Main thread handle...")
time.Sleep(4 * time.Second)
log.Println("Main thread done!")
}
func TestWaitGroup(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
log.Println("Exec task...")
time.Sleep(500 * time.Millisecond)
}
}()
wg.Wait()
log.Println("Main thread done!")
}
func TestGoExit(t *testing.T) {
log.Println("Main thread begin!")
rand.Seed(time.Now().UnixNano())
max := math.MaxInt32
go func() {
for {
num := rand.Intn(max)
result := num % 9 == 0
switch result {
case true:
log.Println("Exit Num:", num)
log.Println("Sub thread exit.")
runtime.Goexit()
default:
time.Sleep(100 * time.Microsecond)
log.Println("Num:", num)
}
}
}()
time.Sleep(10 * time.Second)
log.Println("Main thread done!")
}