我正在生成一些 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/