golang协程管理,程序中断,终止全部协程

197 阅读2分钟

在Go语言中,协程的概念通常被封装在更高级的抽象中,即goroutines。Go运行时负责调度goroutines到操作系统线程上。

要实现程序中断并确保所有goroutines都能优雅地终止,可以使用Go的内置特性,如channels和context包。下面是一些步骤和示例,说明如何实现这一功能。

使用context包来控制goroutines

context包是用于控制goroutine的执行的标准方式。可以通过context来发送取消信号给所有依赖该context的goroutines。

示例代码

这里是一个使用context来控制goroutines的示例,当主函数接收到中断信号时,所有的goroutines将被通知终止。

package main

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

func worker(ctx context.Context, id int, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case <-ctx.Done():
			fmt.Printf("Worker %d is stopping\n", id)
			return
		default:
			fmt.Printf("Worker %d is working\n", id)
			time.Sleep(1 * time.Second)
		}
	}
}

func main() {
	// 创建一个监听系统中断信号的channel
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	// 创建一个context,它可以被取消
	ctx, cancel := context.WithCancel(context.Background())
	wg := sync.WaitGroup{}

	// 启动几个worker goroutines
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go worker(ctx, i+1, &wg)
	}

	// 等待中断信号
	<-sigChan
	fmt.Println("Main received signal, stopping workers...")
	cancel() // 发送取消信号给所有goroutines

	// 等待所有goroutines完成
	wg.Wait()
	fmt.Println("All workers stopped.")
}

如何运行

  1. 运行程序。
  2. 等待一会儿,让workers执行。
  3. 发送中断信号(如在命令行中按Ctrl+C)。
  4. 观察所有goroutines接收取消信号并停止。

解释

  • context.WithCancel(context.Background()) 创建了一个可以被取消的context。
  • worker函数中的select语句监听ctx.Done(),这个channel会在context被取消时关闭。
  • signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 使程序能够监听SIGINT和SIGTERM信号,通常这两个信号用于请求程序终止。
  • 当主函数接收到中断信号时,调用cancel()函数,这会关闭ctx.Done() channel,从而通知所有依赖该context的goroutines停止执行。
  • sync.WaitGroup用于等待所有goroutines完成。

通过这种方式,可以优雅地管理和终止goroutines,而不需要直接与底层交互。