调用 cancel() 函数会改变 context 的状态。这个状态的改变,会被那些正在监听这个 context 的操作所感知,并引发它们相应的行为。
我们把 cancel() 函数触发的影响分为两大类:
- 对
context自身状态的影响。 - 对其他监听此
context的 Go 标准库或用户代码的影响。
1. 对 context 自身状态的影响
当你调用 cancel() 函数时,会发生以下几件事,这些是 context 包内部的行为:
a. ctx.Done() 通道被关闭
这是 context 取消机制的核心。
ctx.Done(): 每个context都有一个Done() <-chan struct{}方法。它返回一个只读通道。- 取消前: 当
context还是活跃状态时,ctx.Done()返回的通道是nil,或者是一个未关闭的通道。任何试图从中接收数据的操作都会阻塞。 - 调用
cancel()后:cancel()函数会立即关闭ctx.Done()返回的那个通道。 - 后果: 在 Go 中,从一个已关闭的通道接收数据会立即成功,并接收到对应类型的零值(这里是
struct{}{}),并且不会阻塞。因此,任何正在监听<-ctx.Done()的 goroutine 都会立即被“唤醒”。
示例代码:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// 创建一个可取消的 context
ctx, cancel := context.WithCancel(context.Background())
// 启动一个 goroutine 来监听 context 的取消
go func() {
fmt.Println("Goroutine: Waiting for cancellation...")
// 这行代码会阻塞,直到 ctx.Done() 通道被关闭
<-ctx.Done()
fmt.Println("Goroutine: Context was canceled!")
}()
// 主 goroutine 等待一秒
time.Sleep(1 * time.Second)
// 主 goroutine 调用 cancel 函数
fmt.Println("Main: Calling cancel()...")
cancel() // <--- 关键动作
// 再等一秒,让 goroutine 有时间打印
time.Sleep(1 * time.Second)
fmt

最低0.47元/天 解锁文章
1226

被折叠的 条评论
为什么被折叠?



