Golang Go语言中 goroutine 在运行中如何关闭的问题

发布于 1周前 作者 sinazl 来自 Go语言

背景是这样的:

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

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


Golang Go语言中 goroutine 在运行中如何关闭的问题
21 回复

创建 job 的时候弄个 context.WithCancal ,在需要的时候调用 cancel 取消掉即可

更多关于Golang Go语言中 goroutine 在运行中如何关闭的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是 2 次不同请求,第二次请求怎么拿到第一次的 goroutine ,goroutine 对象能保存嘛

用 context.WithCancal

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

总之没有那种不侵入代码的写法.

可以用{jobid: cancelFunc}的格式保存,需要结束时获取 cancelFunc 执行一下就行了

楼上正解, 注意下 map 的并发安全问题,以及锁,还有就是加一个定时清理机制就可以解决需求了.

go 不提供这个,需要自己在逻辑里面检测是否需要退出。context 的原理就是传一个 chan 给函数里面,函数自己判断 cancel 是否被调用。

没有办法直接关闭指定的 goroutine ,可以采用曲线救国的方式,在你 goroutine 的业务中做特殊处理通知让其自行结束

感谢 确实是个好思路

谢谢,主要是 2 次请求是不同的 context ,第二次请求如何拿到第一次的 context

像楼上说的那样, 用个全局 map 保存一下(记得加锁), 第一次开始 goroutine 的时候写到 cookie 里一个 key,第二次通过 cookie 里的 key 查询 map, 能找到 就取消掉

生成 jobid 传给前端。点击取消时把 jobid 传回来

或者 redis 或其他存储 点击任务(必定有个 id),redis.set(id, running) 。协程中再开个协程查 redis.get(id)不等于 running 退出

每次点击

if redis.get(id) == running ; redis.set(id,quit) else go func(){redis.set(id,running)

就是 web 开发中的 session 解决的问题,无非是把 context 存在里面罢了

context 持久化就行了,放 redis 之类的缓存中间件就行了

盲猜是任务管理列表

ctx 的 cancel 是个函数不能放 redis 里。建议 11 楼的方法,用 cancel 的化不能无状态动态扩展

#16

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

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

在哪一步启动 ffmpeg 呢

golang<br><br>func main() {<br> ch := make(chan struct{})<br> ctx, cancel := context.WithCancel(context.Background())<br><br> go func(ctx context.Context) {<br> for {<br> select {<br> case &lt;-ctx.Done():<br> ch &lt;- struct{}{}<br> return<br> default:<br> fmt.Println("test11111...")<br> }<br><br> time.Sleep(500 * time.Millisecond)<br> }<br> }(ctx)<br><br> go func() {<br> time.Sleep(3 * time.Second)<br> cancel()<br> }()<br><br> &lt;-ch<br> fmt.Println("结束")<br>}<br>

是这样吗

目前是按 11 楼的做法

但是要结合 ctx cancel ,不然一个 job 如果有多个逻辑,比如 job 里面有执行 a,b,c 三个逻辑块,那么需要把三个逻辑都封装成函数,并且传入 ctx ;当执行第一个逻辑块 a 的时候,收到 ctx cancel ,这个 job 就会退出,并且不会往下执行

在Go语言中,goroutine 是并发执行的基本单位,但直接“关闭”一个 goroutine 并不像在关闭文件或网络连接时那样直接。Go的设计哲学倾向于通过通信来共享内存(CSP模型),而不是通过共享内存来通信,因此关闭 goroutine 通常通过以下几种方式实现:

  1. 通过通道(channel)发送信号:最常见的方法是使用一个无缓冲或带缓冲的通道来向 goroutine 发送停止信号。goroutine 监听这个通道,一旦收到信号就执行清理操作并退出。

  2. 上下文(context)context.Context 是 Go 1.7 引入的,用于在 API 边界之间传递截止日期、取消信号以及其他请求范围的值。可以通过 context 的 Done 通道或 Err() 方法检查是否应该取消操作。

  3. 主动退出:goroutine 内部的逻辑可以检查某些条件,当满足这些条件时主动返回,从而结束执行。这通常与上述的通道或上下文结合使用。

  4. 强制退出:虽然技术上可以通过诸如 runtime.Goexit() 等方法强制退出当前 goroutine,但这通常不推荐,因为它可能导致资源泄漏或死锁,且代码难以维护。

总的来说,优雅地关闭 goroutine 需要设计良好的同步机制,通常是通过通道或上下文来实现。这样的设计不仅符合 Go 的并发模型,也能保证程序的健壮性和可维护性。

回到顶部