
golang 中 context 执行了 cancel,但是
在 golang 中使用 context 来管理子协程时,我们可能会遇到这样的问题:调用 cancel() 方法后,却发现
这种情况通常出现在子协程阻塞在 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
功能说明:1 会员可申请开店功能2 购买在线扣除金额3 冲值卡自动生成4 支持2级分类5 数据库压缩和备份6 会员分5个级别7 商品带讨论8 自带融合论坛,可关闭打开9 密码找回功能10 新闻``滚动新闻``帮助中心11 后台设置前台会员的上传权限12 可关闭/打开商店13 会员自助发布商品功能14 用户问题咨询管理
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号