- 设计思路:
- 使用
context.Context
来管理取消信号。context.Context
是Go语言中用于传递截止时间、取消信号和其他请求范围值的对象。
- 在每一层协程调用时,将
context.Context
作为参数传递下去。这样,当顶层的context
被取消时,所有下层协程都能接收到取消信号。
- 实现代码示例(以Go语言为例):
package main
import (
"context"
"fmt"
"time"
)
// C协程
func CoroutineC(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("CoroutineC收到取消信号,开始清理资源并退出")
// 这里进行资源清理,例如关闭文件、数据库连接等
return
default:
fmt.Println("CoroutineC正在执行任务")
time.Sleep(100 * time.Millisecond)
}
}
}
// B协程
func CoroutineB(ctx context.Context) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go CoroutineC(ctx)
for {
select {
case <-ctx.Done():
fmt.Println("CoroutineB收到取消信号,开始清理资源并退出")
// 这里进行资源清理,例如关闭文件、数据库连接等
return
default:
fmt.Println("CoroutineB正在执行任务")
time.Sleep(100 * time.Millisecond)
}
}
}
// A协程
func CoroutineA(ctx context.Context) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go CoroutineB(ctx)
for {
select {
case <-ctx.Done():
fmt.Println("CoroutineA收到取消信号,开始清理资源并退出")
// 这里进行资源清理,例如关闭文件、数据库连接等
return
default:
fmt.Println("CoroutineA正在执行任务")
time.Sleep(100 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
go CoroutineA(ctx)
time.Sleep(1000 * time.Millisecond)
}
- 不同层级协程资源清理处理:
- 在每一层协程接收到
ctx.Done()
信号后,首先进行本层的资源清理工作。例如,如果协程打开了文件,需要调用file.Close()
关闭文件;如果连接了数据库,需要调用db.Close()
关闭数据库连接等。
- 清理完成后,通过
defer cancel()
(如果有创建子context
)来取消下层协程的context
,确保下层协程也能收到取消信号并进行资源清理。这样,通过层层传递取消信号和清理资源,就能实现整个调用链的优雅关闭。