为了账号安全,请及时绑定邮箱和手机立即绑定

使用 goroutine 的正确方法是什么?

使用 goroutine 的正确方法是什么?

Go
呼唤远方 2021-06-17 02:05:19
我需要对每个请求应用一些测试,并根据测试结果进行响应。如果其中一项测试失败,我需要立即发送响应,否则我会在所有测试成功完成后等待。我想用并发来做那个测试。现在,我这样做(简化):func handler_request_checker(w http.ResponseWriter, r *http.Request) {    done := make(chan bool)    quit := make(chan bool)    counter := 0    go TestOne(r,done,quit)    go TestTwo(r,done,quit)    ..............    go TestTen(r,done,quit)    for {        select {            case <- quit:                fmt.Println("got quit signal")                return            case <- done:                counter++                if counter == 10 {                    fmt.Println("All checks passed succesfully")                    return                }        }    }func main() {    http.HandleFunc("/", handler_request_checker)    http.ListenAndServe()}goroutine 之一的示例:func TestOne(r *http.Request, done,quit chan bool) {    ip,_,ok := net.SplitHostPort(r.RemoteAddr)    if ok == nil {        for _,item := range BAD_IP_LIST {            if strings.Contains(ip,item) {                quit <- true                return            }        }        done <- true        return    } else {        quit <- true        return    }}问题是 goroutines 在我没有退出信号后不会释放内存。我想这是因为在完成的香奈儿里有一些东西。我是 GO 新手,所以也许我用错了方法?例如,当我开始 load check 时http_load -parallel 10 -seconds 10,该 goroutine 很容易吃掉 100+ MB 的 RAM,并且不会将其返还给系统。在下一次检查时,它会多吃 100+ MB,依此类推。如果我在没有go(逐步)的情况下进行测试,则程序在进行任何负载检查时不会超过 10-15mb
查看完整描述

1 回答

?
噜噜哒

TA贡献1784条经验 获得超7个赞

你的猜测是对的。您正在使用同步通道,这意味着发送方和接收方都必须可用才能传输值。

一旦您的handler_request_checker函数收到退出信号,它就会停止检索donequit通道的任何值。此外TestOneTestTwo当他们尝试发送结果时,goroutines 将被阻止。更糟糕的是,它们将永远留在内存中,因为它们仍在运行,因为它们尚未传输结果。

解决该问题的一个方法是使用缓冲(异步)通道donequit。例如:

done := make(chan bool, 10)
quit := make(chan bool, 10)

如果您在 10 个测试中使用大小为 10 的缓冲区,那么所有 goroutine 都能够发送它们的结果,即使不再有可用的读取器。所有 goroutine 将干净地退出,并且一旦所有 goroutine 退出,通道(可能包含一些未读结果)将被垃圾收集。


查看完整回答
反对 回复 2021-06-21
  • 1 回答
  • 0 关注
  • 192 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信