duanjiong1952 2018-05-23 09:39
浏览 114
已采纳

在这种情况下,Go HTTP处理程序goroutine是否应立即退出?

I have one Go HTTP handler like this:

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......")
})

The API works fine, then with curl before the request finish I terminate the curl command deliberately with Control-C, and on server side I do see the client cancelled....................!!!!!!!!! get logged out, but after a while the I am still running........... get logged out also, I thought this goroutine will be terminated immediately!

So, is this desired behaviour, or I did something wrong?

If it is expected, since whatever the goroutine will complete its work, then what is the point of the early cancellation?

If I did something wrong, please help to point me out the correct way.

  • 写回答

1条回答 默认 最新

  • douxianji6104 2018-05-23 09:47
    关注

    You create a contex.Context that can be cancelled, which you do cancel when the client closes the connection, BUT you do not check the context and your handler does nothing differently if it is cancelled. The context only carries timeout and cancellation signals, it does not have the power nor the intent to kill / terminate goroutines. The goroutines themselves have to monitor such cancellation signals and act upon it.

    So what you see is the expected output of your code.

    What you want is to monitor the context, and if it is cancelled, return "immediately" from the handler.

    Of course if you're "sleeping", you can't monitor the context meanwhile. So instead use time.After(), like in this example:

    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......")
    })
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思