Golang Go语言中如何终止一个正在进行的协程?

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

Golang Go语言中如何终止一个正在进行的协程?

利用 context.WithCancel()来终止协程,但存在一个问题:cancel()执行后,必须等 for 循环执行完毕 goroutine 才退出。

for {
  select {
    case <-Ctx.Done():
      return
    default:
      for i := 0; i < 100; i++ {
        // 业务逻辑
      }
  }
}

需求为:cancel()后协程立马退出不再执行后面的循环。
目前我的解决方法:单独起一个协程用来监听退出信号,然后通过全局变量通知业务逻辑循环退出。

flag := false
go func() {
  for {
    select {
      case <-Ctx.Done():
        flag = true
        return
  }
}()

for i:=0; i < 100; i++ { if flag { return } // 业务逻辑 }

请问最佳实践应该是如何退出?


更多关于Golang Go语言中如何终止一个正在进行的协程?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

22 回复

瞎想的,你把 select case 放到 for 循环里面不行?

更多关于Golang Go语言中如何终止一个正在进行的协程?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


for {
for i := 0; i < 100; i++ {
select {
case <-Ctx.Done():
return
default:
// 业务逻辑
}
}
}

<br> for {<br> for i := 0; i &lt; 100; i++ {<br> select {<br> case &lt;-Ctx.Done():<br> return<br> default:<br> // 业务逻辑<br> }<br> }<br> }

这种可以在 for 里每次检测 ctx.Done()… 不过不是最佳实践.
和你图中这个方法差不多, 不过不知道你图中这个方法有没有变量可见性的问题? 导致 flag=true 后在当前协程并不可见?

这样有问题吧,如果不调用 cancel(),最外面 for 循环不会退出。

这个问题我在 java 里面也研究过,最后结果就是无解,只能业务代码里面每次循环都判断

直接退出就不是合理的设计。

执行前检查 Done,

执行后提交前再次检查 Done,根据结果来收尾。

考虑的粒度即使再细都会碰到 执行中取消 这个问题,所以到某个程度之后就 禁止用户取消

如果业务逻辑超时运行或着阻塞,根本走不到 ctx.Done 那个 case 的地方

循环第二位置用 i<100&&ctx.done() 不好么?还非得一个 switch-case ?
至于楼上说的业务阻塞,那就得放到业务里边继续判断了。

多线程运转,直接干掉线程,哈

runtime.Goexit()

Java 里面哪有什么协程?

老哥,你这头像是认真的吗,nft 大佬

#7 java 怎么会无解呢,java 一般就是 Interrupted+状态判断啊

Java 一顿 Interrupt 就行了,只不过没人管 InterruptedException 倒是真的

你这里的 c 表示的是什么呀?

根据我在菜鸟教程学了两天 go 的经验,这个应该是个通道( channel )

#20 if c.ctx != nil {
c.waitDone = make(chan struct{})
go func() {
select {
case <-c.ctx.Done():
c.Process.Kill()
case <-c.waitDone:
}
}()
}

这里的 c 应该不是 channel 吧?

在Go语言中,直接终止一个正在进行的协程(goroutine)是比较复杂且通常不被推荐的做法,因为Go的设计哲学倾向于让协程自行完成其任务或通过通信来协调它们的行为。然而,有几种方法可以在某种程度上实现类似的效果:

  1. 使用上下文(Context): 通过传递一个context.Context对象给协程,可以在需要时取消操作。协程应定期检查该上下文的Done通道是否已关闭,从而决定是否继续执行。

  2. 使用通道(Channel): 创建一个通道,协程在运行时监听该通道的信号。当需要终止协程时,向该通道发送一个信号(如一个特定值或关闭通道),协程收到信号后即可退出。

  3. 使用全局变量或标志: 虽然不推荐,但可以通过全局变量或标志来控制协程的运行。这种方法需要确保对变量的访问是线程安全的。

  4. 使用select语句与超时: 在协程中使用select语句监听多个通道,包括一个用于终止的信号通道。如果收到终止信号,则退出协程。

重要的是,直接强制终止协程(如通过操作系统层面的手段)可能会导致资源泄露、数据不一致或其他未定义行为。因此,建议采用上述更为优雅和安全的方法来控制协程的生命周期。

总之,通过合理的设计和编程模式,可以在Go语言中有效地管理和控制协程的行为。

回到顶部