V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
caicaiwoshishui
V2EX  ›  Go 编程语言

请教一个 goroutine 在运行中,如何关闭的问题

  •  
  •   caicaiwoshishui · 2022-09-28 11:15:50 +08:00 · 2255 次点击
    这是一个创建于 788 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景是这样的:

    用户在页面点击一个执行,这时候会有一个 goroutine job 在 running 中,

    那么用户再次点击停止执行,这次请求如何去关闭上次正在运行的 goroutine ?

    20 条回复    2022-10-06 19:45:24 +08:00
    Sendya
        1
    Sendya  
       2022-09-28 11:26:36 +08:00 via Android
    创建 job 的时候弄个 context.WithCancal ,在需要的时候调用 cancel 取消掉即可
    caicaiwoshishui
        2
    caicaiwoshishui  
    OP
       2022-09-28 11:31:11 +08:00
    @Sendya 这是 2 次不同请求,第二次请求怎么拿到第一次的 goroutine ,goroutine 对象能保存嘛
    MoYi123
        3
    MoYi123  
       2022-09-28 11:31:23 +08:00
    用 context.WithCancal

    还有看 job 是什么类型的, 如果是纯 cpu 计算的, 你要在每几次循环里面确认是否要退出,
    如果是等待网络 io 之类的,需要 select <- ctx.Done()

    总之没有那种不侵入代码的写法.
    rimutuyuan
        4
    rimutuyuan  
       2022-09-28 11:39:35 +08:00   ❤️ 2
    可以用{jobid: cancelFunc}的格式保存,需要结束时获取 cancelFunc 执行一下就行了
    plutome
        5
    plutome  
       2022-09-28 11:46:06 +08:00
    @rimutuyuan 楼上正解, 注意下 map 的并发安全问题,以及锁,还有就是加一个定时清理机制就可以解决需求了.
    Maboroshii
        6
    Maboroshii  
       2022-09-28 11:47:28 +08:00 via Android   ❤️ 1
    go 不提供这个,需要自己在逻辑里面检测是否需要退出。context 的原理就是传一个 chan 给函数里面,函数自己判断 cancel 是否被调用。
    paccco
        7
    paccco  
       2022-09-28 11:51:11 +08:00
    没有办法直接关闭指定的 goroutine ,可以采用曲线救国的方式,在你 goroutine 的业务中做特殊处理通知让其自行结束
    caicaiwoshishui
        8
    caicaiwoshishui  
    OP
       2022-09-28 11:52:55 +08:00
    @rimutuyuan 感谢 确实是个好思路
    caicaiwoshishui
        9
    caicaiwoshishui  
    OP
       2022-09-28 11:54:08 +08:00
    @Maboroshii 谢谢,主要是 2 次请求是不同的 context ,第二次请求如何拿到第一次的 context
    bruce0
        10
    bruce0  
       2022-09-28 12:21:21 +08:00
    @caicaiwoshishui 像楼上说的那样, 用个全局 map 保存一下(记得加锁), 第一次开始 goroutine 的时候写到 cookie 里一个 key,第二次通过 cookie 里的 key 查询 map, 能找到 就取消掉
    dzdh
        11
    dzdh  
       2022-09-28 12:32:21 +08:00   ❤️ 2
    生成 jobid 传给前端。点击取消时把 jobid 传回来

    或者 redis 或其他存储 点击任务(必定有个 id),redis.set(id, running) 。协程中再开个协程查 redis.get(id)不等于 running 退出
    dzdh
        12
    dzdh  
       2022-09-28 12:34:01 +08:00
    每次点击

    if redis.get(id) == running ; redis.set(id,quit) else go func(){redis.set(id,running)
    lanlanye
        13
    lanlanye  
       2022-09-28 13:16:49 +08:00
    就是 web 开发中的 session 解决的问题,无非是把 context 存在里面罢了
    frank1256
        14
    frank1256  
       2022-09-28 14:15:54 +08:00
    @caicaiwoshishui context 持久化就行了,放 redis 之类的缓存中间件就行了
    useben
        15
    useben  
       2022-09-28 21:52:16 +08:00
    盲猜是任务管理列表
    777777
        16
    777777  
       2022-09-29 14:47:17 +08:00
    @frank1256 ctx 的 cancel 是个函数不能放 redis 里。建议 11 楼的方法,用 cancel 的化不能无状态动态扩展
    dzdh
        17
    dzdh  
       2022-09-29 15:40:13 +08:00
    @777777 #16

    有一种情况 拿 ffmpeg 转换视频来说。可能是这样的

    go func(ctx, video-source) { for { select { <ctx.done;

    在哪一步启动 ffmpeg 呢
    guanhui07
        18
    guanhui07  
       2022-09-30 23:19:31 +08:00
    ```golang

    func main() {
    ch := make(chan struct{})
    ctx, cancel := context.WithCancel(context.Background())

    go func(ctx context.Context) {
    for {
    select {
    case <-ctx.Done():
    ch <- struct{}{}
    return
    default:
    fmt.Println("test11111...")
    }

    time.Sleep(500 * time.Millisecond)
    }
    }(ctx)

    go func() {
    time.Sleep(3 * time.Second)
    cancel()
    }()

    <-ch
    fmt.Println("结束")
    }
    ```

    是这样吗
    caicaiwoshishui
        19
    caicaiwoshishui  
    OP
       2022-10-06 19:40:36 +08:00
    @777777 目前是按 11 楼的做法
    caicaiwoshishui
        20
    caicaiwoshishui  
    OP
       2022-10-06 19:45:24 +08:00
    @777777 但是要结合 ctx cancel ,不然一个 job 如果有多个逻辑,比如 job 里面有执行 a,b,c 三个逻辑块,那么需要把三个逻辑都封装成函数,并且传入 ctx ;当执行第一个逻辑块 a 的时候,收到 ctx cancel ,这个 job 就会退出,并且不会往下执行
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   879 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 21:57 · PVG 05:57 · LAX 13:57 · JFK 16:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.