是否有更简洁的方法来创建在通道上接收后取消的上下文?
Is there a more concise way of creating a context that is cancelled after receiving on a channel?
我需要调用一个以 Context
作为参数的函数。此代码块可以访问用于发出应取消操作信号的通道。
这是我目前用来在收到值时取消 Context
的方法:
func doSomething(stop <-chan bool) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
select {
case <-ctx.Done():
case <-stop:
cancel()
}
}()
longRunningFunction(ctx)
}
预期的控制流程如下:
如果任务运行完成,它将取消上下文,<-ctx.Done()
将触发,goroutine 将终止。
如果在 stop
上收到一个值,上下文将被取消,通知任务它应该退出。再一次,当这种情况发生时,goroutine 将终止。
这似乎过于复杂了。有没有更简单的方法来完成预期的行为?
正如@ain 提到的那样,如果 longRunningFunction
运行到最后并且在 stop
上没有发送任何内容(或者它没有关闭),您的代码当前会泄漏 goroutine: select
语句将永远不会实现(context
完成的唯一方法是当某些东西从 stop
出来调用 cancel
时)。
修复方法如下(主要是的实现):
func doSomething(stop <-chan bool) {
ctx := context.TODO() // because in the future, you might pass a ctx arg to this function, from which you could then "inherit"
ctx, cancel := context.WithCancel(ctx)
defer cancel() // to be sure to release the associated resources whatever happens (and prevent the following goroutine from leaking)
go func() {
select {
case <-ctx.Done():
case <-stop:
cancel()
}
}()
longRunningFunction(ctx)
}
我需要调用一个以 Context
作为参数的函数。此代码块可以访问用于发出应取消操作信号的通道。
这是我目前用来在收到值时取消 Context
的方法:
func doSomething(stop <-chan bool) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
select {
case <-ctx.Done():
case <-stop:
cancel()
}
}()
longRunningFunction(ctx)
}
预期的控制流程如下:
如果任务运行完成,它将取消上下文,
<-ctx.Done()
将触发,goroutine 将终止。如果在
stop
上收到一个值,上下文将被取消,通知任务它应该退出。再一次,当这种情况发生时,goroutine 将终止。
这似乎过于复杂了。有没有更简单的方法来完成预期的行为?
正如@ain 提到的那样,如果 longRunningFunction
运行到最后并且在 stop
上没有发送任何内容(或者它没有关闭),您的代码当前会泄漏 goroutine: select
语句将永远不会实现(context
完成的唯一方法是当某些东西从 stop
出来调用 cancel
时)。
修复方法如下(主要是
func doSomething(stop <-chan bool) {
ctx := context.TODO() // because in the future, you might pass a ctx arg to this function, from which you could then "inherit"
ctx, cancel := context.WithCancel(ctx)
defer cancel() // to be sure to release the associated resources whatever happens (and prevent the following goroutine from leaking)
go func() {
select {
case <-ctx.Done():
case <-stop:
cancel()
}
}()
longRunningFunction(ctx)
}