gpt4 book ai didi

go routine 不从 channel 中收集所有对象

转载 作者:IT王子 更新时间:2023-10-29 01:35:09 25 4
gpt4 key购买 nike

我有一个 go-routine 将对象添加到 channel 中,然后我有 4 个 go-routines 来处理 channel 的对象。处理只是将对象添加到数组。但有时,最终数组中缺少对象。所以我假设 channel 在某个时候停止收集对象。我有以下代码:

package main

import (
"log"
"sync"
)

func main() {
j := 0
for {
if j == 10 {
break
}
wg := sync.WaitGroup{}
months := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"}
hits := make(chan string)
i := 0
wg.Add(1)
go func() {
defer close(hits)
for {
if i == 25 {
wg.Done()
return
}
for _, month := range months {
hits <- month
}
i++
}
}()

temp := []string{}
for updateWorker := 1; updateWorker <= 4; updateWorker++ {
wg.Add(1)
go func() {
for hit := range hits {
temp = append(temp, hit)
}
wg.Done()
return
}()
}

wg.Wait()

log.Printf("length of temp %+v\n", len(temp))
j++
}
}

我正在使用 sync 库来同步例程。我正在循环相同的过程 10 次以测试输出是否一致。我期待这样的输出:

length of temp 175

它是 175,因为我发送 7 个月的字符串 25 次。但是有时候输出不到175,不知道为什么。我对 go routines 有点初学者。那么有人可以帮我找到原因吗?谢谢。

最佳答案

问题是 updateWorker goroutines 都从 hits channel 收集结果(到目前为止一切正常),并且它们都将结果存储到 temp 局部变量未同步。这不行。

必须同步访问来自多个 goroutine 的所有变量(其中至少有一个是写入)。

如果您在启用竞争检测器的情况下运行它,它会发出关于数据竞争的尖叫声 (go run -race app.go)。

如果您将 updateWorker goroutines 的数量减少到 1,它会立即产生有效结果,因为这样我们就消除了您应用的单一数据竞争源:

for updateWorker := 1; updateWorker <= 1; updateWorker++ {
// ...
}

如果你想保留多个 updateWorker goroutines,它们对共享 temp 变量的访问必须同步。

sync.Mutex :

var (
mu sync.Mutex
temp []string
)
for updateWorker := 1; updateWorker <= 4; updateWorker++ {
wg.Add(1)
go func() {
for hit := range hits {
mu.Lock()
temp = append(temp, hit)
mu.Unlock()
}
wg.Done()
return
}()
}

另请注意,在这个简单的示例中,通过使用多个 updateWorker goroutines,您将一无所获,添加上述同步(锁定)甚至会降低与仅使用其中一个 goroutines 相比的性能。

要正确分配工作和收集结果,请查看此答案:Is this an idiomatic worker thread pool in Go?

关于go routine 不从 channel 中收集所有对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46664742/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com