go - (goroutine 泄漏)http.TimeoutHandler 不会杀死相应的 ServeHTTP goroutine

标签 go httphandler goroutine timeoutexception

超时处理程序在新的 goroutine 上移动 ServeHTTP 执行,但无法在计时器结束后终止该 goroutine。对于每个请求,它都会创建两个 goroutine,但 ServeHTTP goroutines 永远不会用上下文杀死。

无法找到杀死 goroutines 的方法。

编辑 带有 time.Sleep 函数的 For 循环,代表了超出我们计时器的巨大计算。可以用任何其他功能代替它。

package main

import (
    "fmt"
    "io"
    "net/http"
    "runtime"
    "time"
)

type api struct{}

func (a api) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    // For-loop block represents huge computation and usually takes more time
    // Can replace with any code
    i := 0
    for {
        if i == 500 {
            break
        }
        fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())
        time.Sleep(1 * time.Second)
        i++
    }
    _, _ = io.WriteString(w, "Hello World!")
}

func main() {
    var a api
    s := http.NewServeMux()
    s.Handle("/", a)
    h := http.TimeoutHandler(s, 1*time.Second, `Timeout`)

    fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())

    _ = http.ListenAndServe(":8080", h)
}

ServeHTTP goroutine 应该与请求上下文一起终止,通常情况下不会发生这种情况。

最佳答案

使用context.Context指示 go-routines 中止它们的功能。当然,go-routines 必须监听这样的取消事件。

因此,对于您的代码,请执行以下操作:

ctx := req.Context() // this will be implicitly canceled by your TimeoutHandler after 1s

i := 0
for {
    if i == 500 {
        break
    }

    // for any long wait (1s etc.) always check the state of your context
    select {
    case <-time.After(1 * time.Second): // no cancelation, so keep going
    case <-ctx.Done():
        fmt.Println("request context has been canceled:", ctx.Err())
        return // terminates go-routine
    }
    i++
}

Playground :https://play.golang.org/p/VEnW0vsItXm


注意:Context 被设计为链接 - 允许以级联方式取消多个级别的子任务。

在典型的 REST 调用中,一个人会发起一个数据库请求。因此,要确保及时完成这种阻塞和/或缓慢的调用,而不是使用 Query。应该使用 QueryContext - 将 http 请求的上下文作为第一个参数传递。

关于go - (goroutine 泄漏)http.TimeoutHandler 不会杀死相应的 ServeHTTP goroutine,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56777996/

相关文章:

asp.net - HTTPHandler : IRequiresSessionState halts execution of pages

time - 为什么 sleep 似乎在 goroutine 中不起作用

戈朗 : avoiding race conditions

c# - Generic HttpHandler(一个 ashx,IHttpHandler 接口(interface))什么时候可以重用?

go - 为什么即使有锁,GO 也会出现 'concurrent map writes' panic ?

function - 这个Go函数类型 "HandlerFunc"是怎么工作的,来自标准库 "net/http"

go - 如何通过 go generate 传递参数

go - 安装gobuffalo后如何修复 '/gobuffalo/buffalo/plugins/plugdeps/plugin.go:15:11: undefined: meta.BuildTags'错误

go - Golang 中处理多个错误的最佳实践

c# - 使用page或httphandler输出javascript变量