2 回答
TA贡献1827条经验 获得超8个赞
函数调用和 goroutines 不能被调用者终止,函数和 goroutines 必须支持取消,通常通过context.Context值或done通道。
在任何一种情况下,函数都负责检查/监视上下文,如果请求取消(当上下文的完成通道关闭时),则提前返回。没有更简单/自动的方法。
如果任务在循环中执行代码,一个方便的解决方案是在每次迭代中检查完成的通道,如果它关闭则返回。如果任务是一个“整体”,则实现者负责使用/插入“检查点”,如果请求取消,则可以合理地提前中止任务。
检查 done 通道是否关闭的一种简单方法是使用 non-blocking select,例如:
select {
case <-ctx.Done():
// Abort / return early
return
default:
}
当任务使用其他通道操作时必须小心,因为它们可能会以不确定的方式阻塞。这些选择也应该包括ctx.Done()频道:
select {
case v := <- someChannel:
// Do something with v
case <-ctx.Done():
// Abort / return early
return
}
还要小心,因为如果上面的 receive from someChannelnever 阻塞,则不能保证正确处理取消,因为如果多个通信可以在 a 中进行select,则随机选择一个(并且不能保证<-ctx.Done()永远选择)。在这种情况下,您可以结合上述 2:首先对取消进行非阻塞检查,然后将 aselect与您的通道操作和取消监控一起使用。
TA贡献1752条经验 获得超4个赞
当我们谈到取消时,我们谈到了一个长期运行的函数或一个重复多次的块,例如http.Serve()
至于您的情况,假设saveChunk运行将花费几秒钟,并且您想在保存时取消。所以我们可以把块分成几块,在每一块之后一个接一个地保存。
for i:=0;i<n;i++{
select {
case err := <- s.saveChunk(chunk[i]):
{
if err != nil {
fmt.Errorf("failed saving chunk %w", err)
return
}
}
case <-ctx.Done():
return
}
}
- 2 回答
- 0 关注
- 103 浏览
添加回答
举报