我试图了解Golang并发的最佳实践。我读了O'Reilly关于Go并发的书,然后回到了Golang Codewalks,特别是这个例子:
https://golang.org/doc/codewalk/sharemem/
这是我希望与您一起回顾的代码,以便更多地了解Go。我的第一印象是,这段代码正在破坏一些最佳实践。这当然是我(非常)没有经验的观点,我想讨论并获得对这个过程的一些见解。这不是关于谁对谁错,请好心,我只是想分享我的观点并获得一些反馈。也许这个讨论会帮助其他人理解我为什么错了,并教他们一些东西。
我完全知道这个代码的目的是教初学者,而不是成为完美的代码。
问题 1 - 无 Goroutine 清理逻辑
func main() {
// Create our input and output channels.
pending, complete := make(chan *Resource), make(chan *Resource)
// Launch the StateMonitor.
status := StateMonitor(statusInterval)
// Launch some Poller goroutines.
for i := 0; i < numPollers; i++ {
go Poller(pending, complete, status)
}
// Send some Resources to the pending queue.
go func() {
for _, url := range urls {
pending <- &Resource{url: url}
}
}()
for r := range complete {
go r.Sleep(pending)
}
}
主要方法没有办法清理Goroutines,这意味着如果这是库的一部分,它们将被泄露。
问题 2 - 编写器未生成频道
我认为,作为最佳实践,创建、编写和清理通道的逻辑应由单个实体(或一组实体)控制。这背后的原因是,作者在写入封闭频道时会感到恐慌。因此,编写器最好创建通道,写入该通道并控制何时应关闭该通道。如果有多个写入器,则可以将它们与等待组同步。
func StateMonitor(updateInterval time.Duration) chan<- State {
updates := make(chan State)
urlStatus := make(map[string]string)
ticker := time.NewTicker(updateInterval)
go func() {
for {
select {
case <-ticker.C:
logState(urlStatus)
case s := <-updates:
urlStatus[s.url] = s.status
}
}
}()
return updates
}
此函数不应负责创建更新频道,因为它是频道的读取器,而不是编写器。此通道的编写者应创建它并将其传递给此函数。基本上对功能说“我会通过这个渠道将更新传递给你”。但相反,这个函数正在创建一个通道,目前还不清楚谁负责清理它。
蛊毒传说
www说
相关分类