【发布时间】:2020-09-01 09:47:50
【问题描述】:
我是 Golang 的新手,我有一个使用 WaitGroup 和 Mutex 实现的任务,我想将其转换为使用 Channels。
对该任务的一个非常简短的描述是:根据需要摒弃尽可能多的 go 例程来处理结果,并在主 go 例程中等待并收集所有结果。
我使用WaitGroup和Mutex的实现如下:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func process(input int, wg *sync.WaitGroup, result *[]int, lock *sync.Mutex) *[]int {
defer wg.Done()
defer lock.Unlock()
rand.Seed(time.Now().UnixNano())
n := rand.Intn(5)
time.Sleep(time.Duration(n) * time.Second)
lock.Lock()
*result = append(*result, input * 10)
return result
}
func main() {
var wg sync.WaitGroup
var result []int
var lock sync.Mutex
for i := range []int{1,2,3,4,5} {
wg.Add(1)
go process(i, &wg, &result, &lock)
}
}
如何将使用Mutex 的内存同步替换为使用Channels 的内存同步?
我的主要问题是我不确定如何确定处理最终任务的最终 go 例程,因此让那个例程成为关闭 channel 的例程。这个想法是,通过关闭 channel,主 go 例程可以循环遍历 channel,检索结果,当它看到 channel 已关闭时,它会继续前进。
在这种情况下,关闭频道的方法也可能是错误的,因此我在这里问。
更有经验的 Go 程序员如何使用 channels 解决这个问题?
【问题讨论】:
-
关闭通道是正确的。因为您有多个发送者,所以您仍然需要 WaitGroup,以及一个在 WaitGroup 完成后关闭通道的额外 goroutine。
-
创建一个通道并将其传递给
process,以便它可以发送结果。使用另一个例程等待WaitGroup,然后关闭通道。同时,主要使用range从通道读取结果。 -
@hmm 介意在答案中用代码勾勒出来吗?谢谢
-
与您的问题无关,但有一些建议。在许多 goroutine 中使用
rand包的预制 rng 会导致对 rng 的争用。为了获得更高的性能(如果您的应用程序需要),请在每个 goroutine 中使用rand.New(rand.NewSource( yourSeed ))实例化一个新的 rng。此外,无需在每个 goroutine 中“重新播种”预制的 rng ——只需在程序开始时播种一次即可。
标签: go concurrency coroutine goroutine