【发布时间】:2016-07-03 13:39:04
【问题描述】:
我正在开发一个并发 Go 库,我偶然发现了两种不同的 goroutine 之间的同步模式,它们的结果相似:
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
words := []string{"foo", "bar", "baz"}
for _, word := range words {
wg.Add(1)
go func(word string) {
time.Sleep(1 * time.Second)
defer wg.Done()
fmt.Println(word)
}(word)
}
// do concurrent things here
// blocks/waits for waitgroup
wg.Wait()
}
package main
import (
"fmt"
"time"
)
func main() {
words := []string{"foo", "bar", "baz"}
done := make(chan bool)
// defer close(done)
for _, word := range words {
// fmt.Println(len(done), cap(done))
go func(word string) {
time.Sleep(1 * time.Second)
fmt.Println(word)
done <- true
}(word)
}
// Do concurrent things here
// This blocks and waits for signal from channel
for range words {
<-done
}
}
我被告知sync.WaitGroup 的性能稍好一些,而且我已经看到它被普遍使用。但是,我发现频道更惯用。与频道相比,使用sync.WaitGroup 的真正优势是什么和/或更好的情况可能是什么情况?
【问题讨论】:
-
在您的第二个示例中,同步错误。你阻塞直到第一个 goroutine 在通道上发送,而不是直到最后一个。
-
真正地道,大多数“爆炸”通道(仅用于发送信号的通道)应该具有
chan struct{}类型而不是chan bool。此外,频道在下面使用sync,因此使用sync应该更高效。WaitGroup在您必须阻止等待许多 goroutine 返回时提供帮助。如果您可以在 for 循环中生成 100 个它们,那就更简单了。 -
我尝试运行基于频道的代码,但没有成功。更正的版本在这里。 play.golang.org/p/LHx8Tto-kvI。使用等待组是惯用的,但是如果您想控制并发性,我会担心如何使用等待组来做到这一点。是否有限制等待组。使用通道你可以做到这一点。有一个缓冲通道,然后在该过程完成后读取通道。这样就可以处理下一个项目。
-
@Angelo,我已经更正了你的代码:play.golang.org/p/CglhQg0eVjL(三个 goroutine 没有同时运行,并且始终按此顺序打印“foo bar baz”。)
标签: go concurrency channel