dougou6213
dougou6213
2019-06-26 17:13
浏览 88
已采纳

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

Timeout handler moves ServeHTTP execution on a new goroutine, but not able to kill that goroutine after the timer ends. On every request, it creates two goroutines, but ServeHTTP goroutines never kill with context.

Not able to find a way to kill goroutines.

Edit For-loop with time.Sleep function, represents huge computation which goes beyond our timer. Can replace it with any other function.

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
", 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
", runtime.NumGoroutine())

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

ServeHTTP goroutine should kill along with request context, normally which does not happen.

图片转代码服务由CSDN问答提供 功能建议

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

无法找到一种杀死goroutine的方法。

< strong>编辑带时间的For循环。睡眠功能代表了超出我们计时器的巨大计算量。 可以用其他任何功能替换它。

 包main 
 
import(
“ fmt” 
“ io” \  n“ net / http” 
“运行时” 
“时间” 
)
 
type api struct {} 
 
func(api)ServeHTTP(w http.ResponseWriter,req * http.Request){\  n // for循环块代表着巨大的计算量,通常需要更多时间
 //可以用任何代码替换
i:= 0 
 for {
如果i == 500 {
 break 
} 
 fmt  .Printf(“#goroutines:%d 
”,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 
”,runtime.NumGoroutine())
 
 _ = http.ListenAndServe(“:8080”  ,h)
} 
 
   
 
 

ServeHTTP goroutine应该与请求上下文一起杀死,通常不会 发生。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • douniuta4783
    douniuta4783 2019-07-25 16:15
    已采纳

    I found, if you do not have any way to reach to your channel then there is no way to kill or stop goroutine when it is running.

    In the large computational task, you have to watch the channel on a specific interval or after specific task completion.

    点赞 评论
  • dowb58485
    dowb58485 2019-06-26 18:13

    Use context.Context to instruct go-routines to abort their function. The go-routines, of course, have to listen for such cancelation events.

    So for your code, do something like:

    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


    Note: Context are designed to be chained - allowing for multiple levels of sub-tasks to be canceled in a cascading manner.

    In a typical REST call one would initiate a database request. So, to ensure such a blocking and/or slow call completes in a timely manner, instead of using Query one should use QueryContext - passing in the http request's context as the first argument.

    点赞 评论

相关推荐