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!")
}

posted on 2024-06-28 10:55  进击的davis  阅读(27)  评论(0编辑  收藏  举报

导航