如何解决如果 goroutine 正在运行,则停止它
我有一个类似于 How to stop a goroutine 的问题,但稍有不同。我不确定 goroutine 是否正在运行。
var quit = make(chan bool)
func f1() {
go func() {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-quit:
return
}
}()
}
func f2() {
quit <- true
}
如果在 f2()
之后不到一分钟调用 f1()
,则 goroutine 返回。但是,如果它在一分钟后被调用,goroutine 将已经返回并且 f2()
会阻塞。
如果 goroutine 正在运行,我希望 f2()
取消它,否则什么都不做。
我在这里试图实现的是当且仅当在创建后的一分钟内没有取消任务时才执行任务。
说明:
- 没有什么可以阻止
f2()
被多次调用。 - 一次只有一个 goroutine 在运行。
f1()
的调用者将确保每分钟调用它的次数不会超过一次。
解决方法
使用上下文。
使用可能被取消的上下文运行 f1
。
使用关联的取消函数运行 f2
。
func f1(ctx context.Context) {
go func(ctx context.Context) {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-ctx.Done():
return
}
}(ctx)
}
func f2(cancel context.CancelFunc) {
cancel()
}
然后,为了协调这两个功能,您可以这样做:
ctx,cancel := context.WithCancel(context.Background())
f1(ctx)
f2(cancel)
您还可以尝试使用 context.WithTimeout
函数来合并外部定义的超时。
如果你不知道是否已经有goroutine在运行,你可以像上面一样初始化ctx
和cancel
变量,但不要将它们传递给任何东西。这避免了必须检查 nil
。
记住将 ctx 和 cancel 视为要复制的变量,而不是引用,因为您不希望多个 goroutine 共享内存 - 这可能会导致竞争条件。
,您可以为通道指定缓冲区大小为 1。这意味着您可以向其发送一个值而不会阻塞,即使该值没有立即(或根本没有)收到。
var quit = make(chan bool,1)
我认为最佳答案更好,这只是可以转化为其他情况的另一种解决方案。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。