cancel()
cancel()
取消的是上下文(context
)本身,而不是正在执行的协程。
因此,协程的取消是通过 context
的取消信号来间接实现的。
具体地,协程会在收到 context
的取消信号后自行决定是否退出。
如何使用 cancel()
取消协程?
协程通常会通过检查 context
的状态来判断是否继续执行,cancel()
是通过取消 context
来通知协程停止工作。
以下是如何通过 context
和 cancel()
来控制协程的取消:
示例:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// 创建一个可取消的上下文
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 确保在 main 函数退出时调用 cancel,取消所有相关的协程
// 启动一个新的协程,接收 ctx 来监听取消信号
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
// 当 ctx 被取消时,协程退出
fmt.Println("Task cancelled:", ctx.Err())
return
default:
// 继续执行任务
fmt.Println("Task is running...")
time.Sleep(1 * time.Second)
}
}
}(ctx)
// 主线程等一段时间后取消 ctx
time.Sleep(3 * time.Second)
cancel() // 调用 cancel() 来取消上下文
// 让协程有时间打印取消的消息
time.Sleep(1 * time.Second)
}
代码解释:
context.WithCancel(context.Background())
:创建一个可以手动取消的context
。cancel()
:当我们调用cancel()
时,ctx.Done()
会收到取消信号。所有使用这个ctx
的协程都可以通过ctx.Done()
来接收取消信号并决定退出。- 协程中使用
select
监听ctx.Done()
,一旦context
被取消,协程会停止执行。
cancel()
如何工作:
cancel()
是用来通知与context
相关的操作应该停止。这通常发生在请求超时、手动取消或父上下文取消时。cancel()
会触发上下文的Done()
通道,所有监听这个上下文的协程都可以在Done()
通道中接收到信号,从而安全地停止自己的执行。
总结:
- 取消协程的操作:是通过取消
context
来间接影响协程。cancel()
取消context
,然后协程在收到取消信号后执行相应的退出逻辑。 - 协程通过监听
context.Done()
来判断是否需要退出,而不是通过直接调用cancel()
来停止协程。