
golang 中 context 执行了 cancel,但是 <- ctx.done() 却未执行?
在 golang 中使用 context 来管理子协程时,我们可能会遇到这样的问题:调用 cancel() 方法后,却发现 <- ctx.done() 并未执行。
这种情况通常出现在子协程阻塞在 channel 通信时。以下代码示例可以帮助我们理解这个问题:
package main
import (
"context"
"fmt"
)
func gen(ctx context.context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.done():
fmt.println("done")
default:
n += 1
ch <- n
}
}
}()
return ch
}
func main() {
ctx, cancel := context.withcancel(context.background())
for n := range gen(ctx) {
fmt.println(n)
if n == 5 {
break
}
}
defer cancel()
}在这个示例中,我们希望在打印出数字 5 时取消子协程,并调用 fmt.println("done")。然而,执行后却发现 "done" 并未打印。
立即学习“go语言免费学习笔记(深入)”;
其原因在于,当 cancel() 被调用时,主协程退出,但是子协程仍旧阻塞在 ch <- n 处,因为它等待写入 channel。因此,即使 cancel() 已执行,<- ctx.done() 也不会被触发。
本系统经过多次升级改造,系统内核经过多次优化组合,已经具备相对比较方便快捷的个性化定制的特性,用户部署完毕以后,按照自己的运营要求,可实现快速定制会费管理,支持在线缴费和退费功能财富中心,管理会员的诚信度数据单客户多用户登录管理全部信息支持审批和排名不同的会员级别有不同的信息发布权限企业站单独生成,企业自主决定更新企业站信息留言、询价、报价统一管理,分系统查看分类信息参数化管理,支持多样分类信息,
0
要解决这个问题,我们有两种方法:
1. 关闭 channel
在取消子协程时关闭 channel,这样子协程将在读取 channel 失败后退出。
func gen(ctx context.context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.done():
fmt.println("done")
close(ch)
return
default:
n += 1
ch <- n
}
}
}()
return ch
}2. 使用 time.after 和 select
通过使用 time.after 和 select 来处理超时情况。这样,子协程将同时监听 channel 和超时,并在超时或 context 被取消时退出。
func gen(ctx context.Context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Println("timeout")
case <-ctx.Done():
fmt.Println("done")
default:
n += 1
ch <- n
}
}
}()
return ch
}以上就是Golang 中 Context.Cancel() 后,的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号