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 · 1914 次点击
    这是一个创建于 582 天前的主题,其中的信息可能已经有所发展或是发生改变。

    业务背景是有一个每隔 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 就是这样的,在用户态,不能抢占协程,只能协作
    houshuu
        11
    houshuu  
       2023-04-07 10:44:38 +08:00
    和 7 楼一样, 我以前最类似功能时候也是发现无法在超时情况下直接终结指定 goroutine ,只能分割逻辑到多个 goroutine ,检查上下文是否被 Cancel ,尽量去降低超时后执行的成本。但这样带来的是 goroutine 的一点额外开销,所以如果处理速度很快的任务我觉得不需要这么搞。
    不知道有没有 cgo 相关的手段能改善这个问题。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1225 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:01 · PVG 02:01 · LAX 10:01 · JFK 13:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.