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

时间:2014-02-18 02:01:40

标签: select concurrency garbage-collection go goroutine

让我举个例子:

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("Timed out waiting for string")
  }
}

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

如果快速找到一个字符串,是否还有一个goroutine在某处运行15分钟的睡眠声明,或者这个垃圾是以某种方式收集的?

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

有没有什么方法可以让WaitForString()意识到超时发生并放弃?

1 个答案:

答案 0 :(得分:2)

一般来说,没有办法阻止另一个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("Timed out waiting for string")
}

time.After对于精确的周期性行为非常有用,而time.NewTimer适用于简单的超时。