英文:
Prevent context cancel from stopping function execution in the middle of business logic
问题
有没有一种方法可以保护业务逻辑的执行不受上下文取消的影响?以下是一个代码片段,以更好地理解我的问题。
func main() {
ctx, cancel := context.WithCancel(context.Background())
go foo(ctx)
time.Sleep(time.Second * 3)
cancel()
}
func foo(ctx context.Context) {
// 批量处理数据
// 上下文取消不应该在业务逻辑的中间停止函数执行
for i := 0; i < 10; i++ {
fmt.Println("START of business logic for ID:", i)
fmt.Println("Critical component")
fmt.Print("Saving changes to DB...")
time.Sleep(time.Second * 1)
fmt.Println("Done")
fmt.Println("END of business logic for ID:", i)
}
}
输出:
START of business logic for ID: 0
Critical component
Saving changes to DB...Done
END of business logic for ID: 0
START of business logic for ID: 1
Critical component
Saving changes to DB...Done
END of business logic for ID: 1
START of business logic for ID: 2
Critical component
Saving changes to DB...Done
END of business logic for ID: 2
当执行开始进入循环时,它应该一直执行,直到完成该迭代。使用上下文取消是否可能实现这一点?还是我应该使用其他方法?请给予建议。
英文:
Is there a way to safeguard the execution of business logic from context cancel? Here is the code snippet for a better understanding of my problem
func main() {
ctx, cancel := context.WithCancel(context.Background())
go foo(ctx)
time.Sleep(time.Second * 3)
cancel()
}
func foo(ctx context.Context) {
// batch process data
// context cancel should not stop function execution
// in the middle of business logic
for i:= 0; i<10; i++ {
fmt.Println("START of business logic for ID:", i)
fmt.Println("Critical component")
fmt.Print("Saving changes to DB...")
time.Sleep(time.Second * 1)
fmt.Println("Done")
fmt.Println("END of business logic for ID:", i)
}
}
Output:
START of business logic for ID: 0
Critical component
Saving changes to DB...Done
END of business logic for ID: 0
START of business logic for ID: 1
Critical component
Saving changes to DB...Done
END of business logic for ID: 1
START of business logic for ID: 2
Critical component
Saving changes to DB...Done
END of business logic for ID: 2
When the execution starts in the for loop, it should not stop until it finishes that iteration. Is this possible with using context cancel? or should I use another approach, please suggest.
答案1
得分: 2
上下文取消是一种向任务发送信号的机制。它不能确保强制执行 - 这取决于任务本身。这允许任务在中止整个操作之前完成关键的子任务。
因此,在你的理论示例中,任何关键的子步骤都应该忽略取消操作 - 只有在它们完成后才轮询上下文:
select {
case <-ctx.Done():
return ctx.Err() // 我们被取消了,中止操作
default:
}
编辑:应用到你的示例
for i := 0; i < 10; i++ {
//
// 关键部分
//
// ...
select {
case <-ctx.Done():
return ctx.Err() // 我们被取消了,中止操作
default:
}
}
https://play.golang.org/p/kZ39VEVyP4L
英文:
Context cancelation is a signal mechanism to a task. It does not ensure enforcement - that is left up to the task. This allows a task to finish up critical sub-tasks before aborting the larger operation.
So in your theoretical example any critical sub-steps should ignore cancelation - and only after they are complete poll the context:
select {
case <-ctx.Done():
return ctx.Err() // we're cancelled, abort
default:
}
EDIT: applying to your example
for i := 0; i < 10; i++ {
//
// critical section
//
// ...
select {
case <-ctx.Done():
return ctx.Err() // we're cancelled, abort
default:
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论