在这种情况下,Go HTTP 处理程序 goroutine 是否应该立即退出?
Is the Go HTTP handler goroutine expected to exit immediately in this case?
我有一个这样的 Go HTTP 处理程序:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
time.Sleep(5 * time.Second)
fmt.Println("I am still running...........")
fmt.Fprint(w, "cancellation testing......")
})
API 工作正常,然后在请求完成之前使用 curl 我故意用 Control-C
终止 curl 命令,在服务器端我确实看到 client cancelled....................!!!!!!!!!
被注销, 但过了一会儿 I am still running...........
也被注销了,我以为这个 goroutine 会立即终止!
那么,这是期望的行为,还是我做错了什么?
如果是预期的话,既然goroutine会完成它的工作,那么提前取消的意义何在?
如果我做错了,请帮我指出正确的方法。
您创建了一个可以取消的 contex.Context
,当客户端关闭连接时您确实取消了它,但是您没有检查上下文,如果它被取消,您的处理程序也没有做任何不同的事情。上下文仅 携带 超时和取消信号,它没有权力也没有意图杀死/终止 goroutines。 goroutines 本身必须监视此类取消信号并对其采取行动。
所以您看到的是代码的预期输出。
你要的是监控上下文,如果取消了,return"immediately"从handler.
当然,如果您是"sleeping",则无法同时监视上下文。所以改为使用 time.After()
,如本例所示:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
select {
case <-time.After(5 * time.Second):
fmt.Println("5 seconds elapsed, client didn't close")
case <-ctx.Done():
fmt.Println("Context closed, client closed connection?")
return
}
fmt.Fprint(w, "cancellation testing......")
})
我有一个这样的 Go HTTP 处理程序:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
time.Sleep(5 * time.Second)
fmt.Println("I am still running...........")
fmt.Fprint(w, "cancellation testing......")
})
API 工作正常,然后在请求完成之前使用 curl 我故意用 Control-C
终止 curl 命令,在服务器端我确实看到 client cancelled....................!!!!!!!!!
被注销, 但过了一会儿 I am still running...........
也被注销了,我以为这个 goroutine 会立即终止!
那么,这是期望的行为,还是我做错了什么?
如果是预期的话,既然goroutine会完成它的工作,那么提前取消的意义何在?
如果我做错了,请帮我指出正确的方法。
您创建了一个可以取消的 contex.Context
,当客户端关闭连接时您确实取消了它,但是您没有检查上下文,如果它被取消,您的处理程序也没有做任何不同的事情。上下文仅 携带 超时和取消信号,它没有权力也没有意图杀死/终止 goroutines。 goroutines 本身必须监视此类取消信号并对其采取行动。
所以您看到的是代码的预期输出。
你要的是监控上下文,如果取消了,return"immediately"从handler.
当然,如果您是"sleeping",则无法同时监视上下文。所以改为使用 time.After()
,如本例所示:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
select {
case <-time.After(5 * time.Second):
fmt.Println("5 seconds elapsed, client didn't close")
case <-ctx.Done():
fmt.Println("Context closed, client closed connection?")
return
}
fmt.Fprint(w, "cancellation testing......")
})