这个 goroutine 泄露的 demo 如何修复? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
xoxo419
V2EX    Go 编程语言

这个 goroutine 泄露的 demo 如何修复?

  •  
  •   xoxo419 2021-12-30 09:43:31 +08:00 3510 次点击
    这是一个创建于 1386 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func main() { for i := 0; i < 4; i++ { queryAll() fmt.Printf("goroutines: %d\n", runtime.NumGoroutine()) } } func queryAll() int { ch := make(chan int) for i := 0; i < 3; i++ { go func() { ch <- query() }() } return <-ch } func query() int { n := rand.Intn(100) time.Sleep(time.Duration(n) * time.Millisecond) return n } 
    第 1 条附言    2021-12-30 19:31:28 +08:00
    只是单纯讨论 goroutine 泄漏的一个 demo ,想从这个 demo 去学习如何分析泄露和修复的过程而已~
    18 条回复    2022-01-10 06:51:32 +08:00
    iyear
        1
    iyear  
       2021-12-30 09:55:41 +08:00 via Android
    写三次,就读了一次当然剩下两个阻塞出不来了
    wangdashuai
        2
    wangdashuai  
       2021-12-30 10:04:52 +08:00
    写个 woker 池处理,这样能保证 goroutine 数量不随任务增加。
    CEBBCAT
        3
    CEBBCAT  
       2021-12-30 10:07:44 +08:00 via Android
    queryAll 中的协程加上 select
    keepeye
        4
    keepeye  
       2021-12-30 10:10:31 +08:00
    不知道这个例子的想实现什么功能,仅为了修复而修复的话,可以给 chan 加上 buffer 或者写的时候用 select 就不会阻塞了
    vizee
        5
    vizee  
       2021-12-30 10:14:00 +08:00
    ch := make(chan int, 3)

    脑筋急转弯是吧
    gamexg
        6
    gamexg  
       2021-12-30 10:34:59 +08:00   1
    如楼上,建立 3 缓冲区的 chan

    或者写的时候检查是否已满。

    select {
    case ch <- query():
    default:
    }
    gamexg
        7
    gamexg  
       2021-12-30 10:43:12 +08:00
    @gamexg #6 select 也要保证 chan 至少有 1 的缓冲区
    xiaoFine
        8
    xiaoFine  
       2021-12-30 11:01:04 +08:00
    小白一问,试了下诸君的方法,并不行啊
    1. buffer ch
    ```
    func queryAll() int {
    ch := make(chan int, 3)

    for i := 0; i < 3; i++ {
    go func() { ch <- query() }()
    }
    return <-ch
    }
    /**
    goroutines: 3
    goroutines: 5
    goroutines: 5
    goroutines: 7
    **/
    ```
    2. select
    ```
    func queryAll() int {
    ch := make(chan int, 3)

    for i := 0; i < 3; i++ {
    go func() {
    select {
    case ch <- query():
    default:

    }
    }()
    }
    return <-ch
    }
    /**
    goroutines: 3
    goroutines: 5
    goroutines: 5
    goroutines: 7
    **/
    ```
    xiaoFine
        9
    xiaoFine  
       2021-12-30 11:26:38 +08:00
    目前能想到的只能是这样(不改变签名),有更优雅的方法吗。。
    ```
    func queryAll() int {
    ch := make(chan int)

    for i := 0; i < 3; i++ {
    go func() {ch <- query()}()
    }
    <-ch
    <-ch
    return <-ch
    }
    /**
    goroutines: 1
    goroutines: 1
    goroutines: 1
    goroutines: 1
    **/
    ```
    hzzhzzdogee
        10
    hzzhzzdogee  
       2021-12-30 12:06:35 +08:00
    @xiaoFine #8 因为 100 毫米以后 query()才返回, 你直接打印 runtime.NumGoroutine()当然会不正确. 实际上 goroutine 并没有泄露
    ikw
        11
    ikw  
       2021-12-30 12:08:55 +08:00   1
    @xiaoFine #8 单从解决 Goroutine 泄漏来说,query 里有 sleep ,你得等 query 跑完了再打 Goroutine 数量,就能看到数量只有 1 ,但是确实让人想不明白写 3 次,读 1 次这个逻辑意义是什么
    xiaoFine
        12
    xiaoFine  
       2021-12-30 15:27:55 +08:00
    @zwpaper 我能找到的最早的出处是这样 https://medium.com/golangspec/goroutine-leak-400063aef468 ,应该就是单纯讨论 goroutine 泄漏的一个 demo ,不过确实学到了
    index90
        13
    index90  
       2021-12-30 19:24:58 +08:00   1
    所有 goroutine 都需要有个 ctx 或者类似的“控制线”,并且独立于“数据线”
    在业务逻辑结束之前,通过关闭“控制线”来结束所有 goroutine
    SorcererXW
        14
    SorcererXW  
       2021-12-30 21:27:19 +08:00
    写的时候 select 一下或者用 sync.once 包起来保证只写一次 channel
    更好的办法是传一个 context 进去,外部 defer 里面执行一下 cancel
    gjquoiai
        15
    gjquoiai  
       2021-12-31 18:58:44 +08:00
    你这个只能叫背压 demo ,并没有东西泄漏
    zinwalin
        16
    zinwalin  
       2022-01-07 16:01:26 +08:00
    为啥我能运行起来
    xoxo419
        18
    xoxo419  
    OP
       2022-01-10 06:51:32 +08:00   1
    @zinwalin 是可以运行的,泄露只是程序运行的越久占用内存就会越高 最后导致程序无响应
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1502 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 16:30 PVG 00:30 LAX 09:30 JFK 12:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86