我有几个例程,我使用无缓冲通道作为同步机制。
我想知道这是否有任何问题(例如,与WaitGroup实现相比)。我知道的一个已知“缺点”是两个go例程可能会保持阻塞,直到第3个(最后一个)完成,因为通道没有缓冲,但我不知道内部/什么这真的意味着。
func main() {
chan1, chan2, chan3 := make(chan bool), make(chan bool), make(chan bool)
go fn(chan1)
go fn(chan2)
go fn(chan3)
res1, res2, res3 := <-chan1, <-chan2, <-chan3
}
答案 0 :(得分:0)
这种实现本身并不是更糟或更好,而且我已经编写了这种风格的代码,转而使用WaitGroup
成功。我还使用WaitGroup
实现了相同的功能,结果大致相同。正如评论中所提到的那样,情境更好,在许多情况下可能是主观的(差异在于可维护性或可读性而非性能)。
就个人而言,我真的很喜欢这种风格,因为我会在一个系列中为每个项目分拆一个工人。我已经遇到了很多关于干净地关闭的痛苦(在中止或关闭通道上的信号,必须以这种或那种方式提供给工人方法)所以我认为将通信循环更进一步是非常方便的并将所有工作包含在频道选择中。无论如何,你必须要有一个工作中止。
答案 1 :(得分:0)
频道和WaitGroup
都可供您根据需要使用。对于给定的问题,您的解决方案可以使用渠道或WaitGroup
或甚至两者的组合来解决。
据我所知,当你的goroutine需要相互沟通时,渠道更合适(因为它们不是独立的)。当你的goroutine彼此独立时,通常会使用WaitGroup
。
就个人而言,我喜欢WaitGroup
,因为它更易读,更易于使用。但是,就像通道一样,我不喜欢我们需要将引用传递给goroutine,因为这意味着并发逻辑将与您的业务逻辑混合。
所以我想出了这个通用函数来解决这个问题:
// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
var waitGroup sync.WaitGroup
waitGroup.Add(len(functions))
defer waitGroup.Wait()
for _, function := range functions {
go func(copy func()) {
defer waitGroup.Done()
copy()
}(function)
}
}
以下是一个例子:
func1 := func() {
for char := 'a'; char < 'a' + 3; char++ {
fmt.Printf("%c ", char)
}
}
func2 := func() {
for number := 1; number < 4; number++ {
fmt.Printf("%d ", number)
}
}
Parallelize(func1, func2) // a 1 b 2 c 3
如果您想使用它,可以在https://github.com/shomali11/util
找到它