在 Go 中处理 Unix 信号

GolangGolangBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

信号实验(Signals lab)展示了如何在Go程序中使用通道来处理Unix信号。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/NetworkingGroup(["Networking"]) go/NetworkingGroup -.-> go/signals("Signals") subgraph Lab Skills go/signals -.-> lab-15505{{"在 Go 中处理 Unix 信号"}} end

信号

在某些情况下,我们希望我们的Go程序能够智能地处理Unix信号。例如,我们可能希望服务器在接收到 SIGTERM 时优雅地关闭,或者命令行工具在接收到 SIGINT 时停止处理输入。

  • 创建一个带缓冲的通道来接收 os.Signal 通知。
  • 使用 signal.Notify 注册该通道以接收指定信号的通知。
  • 创建一个 goroutine 来执行对信号的阻塞接收。
  • 打印接收到的信号并通知程序可以结束。
  • 等待预期的信号,然后退出。
## 当我们运行这个程序时,它将阻塞并等待信号。通过输入 `ctrl-C`(终端显示为 `^C`),我们可以发送一个 `SIGINT` 信号,使程序打印 `interrupt` 然后退出。
$ go run signals.go
awaiting signal
^C
interrupt
exiting

以下是完整代码:

// 有时我们希望我们的Go程序能够智能地处理 [Unix信号](https://en.wikipedia.org/wiki/Unix_signal)。
// 例如,我们可能希望服务器在接收到 `SIGTERM` 时优雅地关闭,或者命令行工具在接收到 `SIGINT` 时停止处理输入。
// 以下是如何使用通道在Go中处理信号。

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

func main() {

	// Go信号通知通过在通道上发送 `os.Signal` 值来工作。我们将创建一个通道来接收这些通知。请注意,这个通道应该是带缓冲的。
	sigs := make(chan os.Signal, 1)

	// `signal.Notify` 注册给定的通道以接收指定信号的通知。
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// 我们可以在主函数中从 `sigs` 接收,但让我们看看如何也可以在一个单独的goroutine中完成,以演示更实际的优雅关闭场景。
	done := make(chan bool, 1)

	go func() {
		// 这个goroutine执行对信号的阻塞接收。当它收到一个信号时,它会将其打印出来,然后通知程序可以结束。
		sig := <-sigs
		fmt.Println()
		fmt.Println(sig)
		done <- true
	}()

	// 程序将在这里等待,直到它收到预期的信号(如上面的goroutine在 `done` 上发送一个值所指示的),然后退出。
	fmt.Println("awaiting signal")
	<-done
	fmt.Println("exiting")
}

总结

信号实验(Signals lab)展示了如何在Go程序中使用通道来处理Unix信号。通过创建一个带缓冲的通道来接收 os.Signal 通知,并使用 signal.Notify 注册该通道以接收指定信号的通知,我们可以优雅地处理信号,并在接收到预期信号时退出程序。