go - 试图避免 goroutine 泄漏时出现 panic

标签 go memory-leaks goroutine

我正在生成一些 goroutine,并希望为它们提供一个发送回错误的 channel 。在父 Goroutine 中,我选择第一个错误并返回该错误,或​​者 wg.Done() 条件,该条件与关闭 done 同步> channel 。

推迟 errc 的关闭以避免 goroutine 泄漏;但它会导致竞争条件。

package main

import (
    "log"
    "sync"
    "time"
)

func f(ch chan<- bool, wg *sync.WaitGroup) {
    defer wg.Done()

    time.Sleep(1 * time.Second)
    log.Println("f sending a value")
    ch <- true
    log.Println("f sent a value")
}

func g(ch chan<- bool, wg *sync.WaitGroup) {
    defer wg.Done()

    time.Sleep(2 * time.Second)
    log.Println("g sending a value")
    ch <- true
    log.Println("g sent a value")
}

func main() {
    var wg sync.WaitGroup

    ch := make(chan bool)
    bufc := make(chan bool, 2)

    defer func() {
        log.Println("Closing bufc")
        close(bufc)
        log.Println("Closed bufc")
        time.Sleep(5 * time.Second)
    }()

    wg.Add(2)
    go f(bufc, &wg)
    go g(bufc, &wg)
    go func() {
        wg.Wait()
        close(ch)
    }()

    select {
    case done, ok := <-bufc:
        log.Printf("bufc closed: %v %v", done, ok)
    case <-ch:
        log.Println("ch was closed")
    }
}

结果:

❗ ~/c/scrap
(i) go run test.go
2018/05/01 20:28:03 f sending a value
2018/05/01 20:28:03 f sent a value
2018/05/01 20:28:03 bufc closed: true true
2018/05/01 20:28:03 Closing bufc
2018/05/01 20:28:03 Closed bufc
2018/05/01 20:28:04 g sending a value
panic: send on closed channel

goroutine 19 [running]:
main.g(0xc42009c000, 0xc42008a010)
        /Users/yangmillstheory/code/scrap/test.go:23 +0xb2
created by main.main
        /Users/yangmillstheory/code/scrap/test.go:42 +0x11e
exit status 2

有什么方法可以正确清理 errc channel 而不引起 panic ?我是否需要关闭errc?鉴于它是缓冲的,该 channel 上的发件人不会阻塞,所以我猜答案是否定的?

最佳答案

您的错误足够清楚 - channel bufc (我假设您将其称为 errc)在 g 可以发送之前关闭因为 select 语句仅从 bufc 接收一次并且它通过 defer 关闭。您必须进行一些同步,而不是推迟 bufc 的关闭,例如,可能使用 sync.WaitGroup 来确保在关闭它之前发送所有值只需将 close(bufc) 移至 wg.Wait() 之后:

go func() {
        wg.Wait()
        close(ch)
        close(bufc)
}()

在你的情况下,由于 bufc 被缓冲,你不必关闭它,因为它不会在接收端阻塞,但是一旦你有两个以上的 goroutine 发送,你仍然需要关闭它它可以正确发出信号。

关于go - 试图避免 goroutine 泄漏时出现 panic ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50126750/

相关文章:

mysql - CREATE PROCEDURE语句中的SQL语法错误1604

java - 查找谁分配直接内存的有效方法

iphone - 如何在不使我的应用程序崩溃的情况下发布此 NSXMLParser?

c++ - 从 C++ 中的函数返回引用的推荐方法

multithreading - 关于 Goroutines 的 Golang 内存泄漏

go - 当 main 退出时,goroutines 会运行 defer() 吗?

使用 http.server 转到上下文

go - 无法在elasticsearch中保存UUID

json - 如何动态地包含/排除 JSON 中的结构字段?

go - 有没有更好的选择去使用常规 sleep