我正在试图弄清楚如何使用Go中的上下文模式。 我正在模拟由于执行超时而需要取消多个长时间运行的子goroutine的情况。据我所知,上下文的一个主要用法是在I / O超时或用户离开页面之前停止所有子进程。
我的代码:
package main
import (
"context"
"fmt"
"time"
)
func doIt(ctx context.Context, filename string) {
// simulate not ending file processing -
// internals of this loop could not change
// e.g. it is call of some third party or stdlib function that hangs
for {
fmt.Printf("processing file %s\n", filename)
time.Sleep(50 * time.Millisecond)
}
}
func main() {
startFileProcessing()
fmt.Println("End of processing")
time.Sleep(500 * time.Millisecond)
fmt.Println("Do something else")
}
func startFileProcessing() {
// set file processing timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100)
defer cancel()
// start two parallel processes
go doIt(ctx, "file1")
go doIt(ctx, "file2")
select {
case <-ctx.Done():
fmt.Println("file processing timeout")
return
}
}
哪个输出:
processing file file2
processing file file1
processing file file1
processing file file2
processing file file1
file processing timeout
End of processing
processing file file2
processing file file2
processing file file1
processing file file1
processing file file2
Do something else
我预计在“文件处理超时”之后不会看到“处理文件”行。
如何解决?
编辑: @Mellow Marmot指出,上下文并没有阻止儿童goroutines自己提出解决方案。但是他的更改是在doIt函数的循环内部完全没有回答的问题,因为在doIt函数中可能存在一些无法更改的第三方(或stdlib)函数调用。
所以让我重新解释一下问题 -
如何取消一些长时间运行的进程到我的内部 没有访问权限 - 挂起的时间超过超时?
答案 0 :(得分:3)
上下文不会自行阻止子goroutines。在goroutine中运行的应用程序代码必须检查上下文并在完成上下文时从goroutine返回。以下是如何检查上下文的示例:
func doIt(ctx context.Context, filename string) {
// simulate not ending file processing
for {
fmt.Printf("processing file %s\n", filename)
time.Sleep(50 * time.Millisecond)
select {
case <-ctx.Done():
return
default:
}
}
}
除非在goroutine中执行的代码提供了这样做的机制,否则无法取消长时间运行的goroutine。没有机制可以杀死goroutine中执行的代码外部的goroutine。