Golang 怎么 Cancel 一个非循环子协程 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
hentailolicon
V2EX    Go 编程语言

Golang 怎么 Cancel 一个非循环子协程

  •  2
     
  •   hentailolicon 2023-04-02 03:47:29 +08:00 2325 次点击
    这是一个创建于 943 天前的主题,其中的信息可能已经有所发展或是发生改变。

    业务背景是有一个每隔 10 秒执行一次的任务,这个任务会拿很多数据还有分析耗时会长一点,处理完后会给 chan 发数据.

    然后数据修改的时候会调用 context 的 cancel 去停止协程, 但是只能停止 10s 定时任务这个协程,不能把还在处理这个任务也停止掉,会出现脏数据传到 chan 里

    有没有什么好的方法能让他在执行一半的时候直接被 cancel 掉

    11 条回复    2023-04-07 10:44:38 +08:00
    blessingsi
        1
    blessingsi  
       2023-04-02 04:23:36 +08:00 via Android
    一个协程,同时 wait context.cancel 和那个 worker 的处理结果。拿到 cancel 不处理,拿到处理结果时写入 chan
    keakon
        2
    keakon  
       2023-04-02 08:46:14 +08:00
    没有优雅的实现。
    其他语言可以给拿数据的连接设置 read timeout ,或者用子进程来处理。
    但是 Go 把连接给封装了,大部分数据库的接口是同步的,你没法同时监听 fd 可读和定时器超时。
    子进程要传数据需要用 pipe ,但是它的 Read()/Write() 是同步的,需要再起个协程去读写,才能和监听子进程退出和超时一起 select 。而且 Go 的 runtime 和第三方库可能都跑了一些子线程,fork 时并不会复制这些子线程,导致有时候会崩溃。
    MarsCloud
        3
    MarsCloud  
       2023-04-02 11:27:33 +08:00
    或者可以简化一点,无需立马取消掉;而是在将数据写入 chan 之前,先做个判断,任务正常则将数据写入 chan ;反之则跳过写数据的步骤,直接结束任务。
    wqtacc
        4
    wqtacc  
       2023-04-02 21:15:02 +08:00
    传递上下文,在需要的位置使用,比如在这里避免脏数据的话,向 chan 写数据之前的某个地方检查上下文是否超时或者已经 canceled
    ```go
    select {
    case <- ctx.Done():
    default:
    }
    hentailolicon
        5
    hentailolicon  
    OP
       2023-04-02 22:30:05 +08:00
    @wqtacc 这样其实还是得让他走完流程, 旧数据都没有做并发支持只用的原生 map
    lysS
        6
    lysS  
       2023-04-03 12:46:13 +08:00
    “这个任务会拿很多数据还有分析耗时会长一点”;把这个任务拆分成小任务,然后每个小任务中间检查 ctx done
    777777
        7
    777777  
       2023-04-03 17:52:33 +08:00
    这问题我研究过:没有办法杀死正在运行的协程,只能把你的任务分为多个多个小任务然后检查 ctx
    hentailolicon
        8
    hentailolicon  
    OP
       2023-04-03 21:14:32 +08:00
    @lysS 这样写也太丑了啊
    wqtacc
        9
    wqtacc  
       2023-04-03 23:20:38 +08:00
    @hentailolicon 正常是这么做的,一般会在循环中加入检查 ctx.Done, 比如说在从流中读取数据,读取下一条数据等等,像 lysS 说的将任务实现为单一功能的小任务;
    lysS
        10
    lysS  
       2023-04-04 09:53:13 +08:00
    @hentailolicon ctx 就是这样的,在用户态,不能抢占协程,只能协作
    fang2hou
        11
    fang2hou  
       2023-04-07 10:44:38 +08:00
    和 7 楼一样, 我以前最类似功能时候也是发现无法在超时情况下直接终结指定 goroutine ,只能分割逻辑到多个 goroutine ,检查上下文是否被 Cancel ,尽量去降低超时后执行的成本。但这样带来的是 goroutine 的一点额外开销,所以如果处理速度很快的任务我觉得不需要这么搞。
    不知道有没有 cgo 相关的手段能改善这个问题。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2549 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 13:55 PVG 21:55 LAX 06:55 JFK 09:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86