我可以强制终止一个 goroutine 而不等待它返回吗?

huangapple go评论90阅读模式
英文:

Can I force termination a goroutine without waiting for it to return?

问题

让我举个例子:

func WaitForStringOrTimeout() (string, error) {
  my_channel := make(chan string)
  go WaitForString(my_channel)
  
  select {
  case found_string := <-my_channel:
    return found_string, nil
  case <-time.After(15 * time.Minute):
    return nil, errors.New("等待字符串超时")
  }
}

在这个简单的例子中,我有一个名为WaitForString的函数,它会阻塞一段时间,最终可能返回一个字符串。我想用这段代码包装WaitForString函数,它要么返回相同的字符串,要么在超时时返回错误。

如果字符串很快被找到,那么是否还有一个带有15分钟睡眠语句的goroutine在运行,或者它会被垃圾回收?

如果超时发生并且字符串从未被找到,那么是否仍然有一个运行WaitForString的goroutine,即使没有其他例程可以观察它的输出?如果WaitForString分配了大量内存但从不返回会怎样?

有没有办法让WaitForString()意识到超时发生并放弃执行?

英文:

Let me use an example:

func WaitForStringOrTimeout() (string, error) {
  my_channel := make(chan string)
  go WaitForString(my_channel)
  
  select {
  case found_string := &lt;-my_channel:
    return found_string, nil
  case  &lt;-time.After(15 * time.Minute):
    return nil, errors.New(&quot;Timed out waiting for string&quot;)
  }
}

In this simple example, I have some function WaitForString which blocks for awhile and eventually may return a string. I want to wrap WaitForString with this code which either returns the same string or times out with an error.

If a string is found quickly, is there still a goroutine running with a 15 minute sleep statement somewhere or is this garbage collected somehow?

If the timeout occurs and a string is never found, is there still a goroutine running WaitForString, even though there are no other routines that could observe it's output? What if WaitForString allocates a lot of memory but never returns?

Is there some way I can make WaitForString() become aware of the timeout occurring and give up?

答案1

得分: 3

通常情况下,没有办法停止另一个goroutine。有一个名为runtime.Goexit的函数可以用来使当前的goroutine退出(即使在深层调用帧中调用),但没有办法使其他goroutine退出。

对于time模块的特定情况,没有单独的goroutine处理每个计时器或定时器:相反,计时器由运行时集中管理,以便它可以知道下次何时需要唤醒。

虽然没有goroutine挂起,但通道和一个小的记录结构将保留15分钟。

如果这是一个问题,考虑使用time.NewTimer而不是time.After,并在返回时手动停止计时器。例如:

t := time.NewTimer(15 * time.Minute)
defer t.Stop()
select {
case found_string := <-my_channel:
    return found_string, nil
case <-t.C:
    return nil, errors.New("等待字符串超时")
}

time.After对于精确的周期行为非常有用,而time.NewTimer对于简单的超时操作也很好用。

英文:

In general, no there isn't a way to stop another goroutine. There is a runtime.Goexit function that can be used to cause the current goroutine to exit (even if called from a deep call frame), but nothing to cause other goroutines to exit.

For the specific case of the time module, there isn't a separate goroutine handling each timer or ticker: instead, timers are centrally managed by the runtime so it can tell when it next needs to wake up.

While there's no goroutine hanging around, the channel and a small bookkeeping struct will stick around for the 15 minutes.

If this is a problem, consider using time.NewTimer instead of time.After, and manually stop the timer when you return. For example:

t := time.NewTimer(15 * time.Minute)
defer t.Stop()
select {
case found_string := &lt;-my_channel:
    return found_string, nil
case  &lt;-t.C:
    return nil, errors.New(&quot;Timed out waiting for string&quot;)
}

time.After is really useful for exact periodic behaviour, whereas time.NewTimer works fine for simple timeouts.

huangapple
  • 本文由 发表于 2014年2月18日 10:01:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/21842963.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定