go - 使用 goroutines 处理值并将结果收集到 slice 中

标签 go slice goroutine

我最近在探索 Go 以及 goroutines 的工作方式让我感到困惑。

我尝试使用 goroutines 将我之前编写的代码移植到 Go 中,但出现了 fatal error: all goroutines are asleep - deadlock! 错误。

我想做的是使用 goroutines 处理列表中的项目,然后将处理后的值收集到一个新列表中。但是我在“收集”部分遇到了问题。

代码:

sampleChan := make(chan sample)
var wg sync.WaitGroup

// Read from contents list
for i, line := range contents {
    wg.Add(1)
    // Process each item with a goroutine and send output to sampleChan
    go newSample(line, *replicatePtr, *timePtr, sampleChan, &wg)
}
wg.Wait()

// Read from sampleChan and put into a slice
var sampleList []sample
for s := range sampleChan {
    sampleList = append(sampleList, s)
}
close(sampleChan)

从 goroutines 收集结果的正确方法是什么?

我知道 slice 不是线程安全的,所以我不能让每个 goroutine 都附加到 slice 上。

最佳答案

您的代码几乎是正确的。有几个问题:首先,您在收集结果之前等待所有工作人员完成,其次,您的 for 循环在 channel 关闭时终止,但 channel 仅在for 循环终止。

您可以通过在工作人员完成时异步关闭 channel 来修复代码:

for i, line := range contents {
    wg.Add(1)
    // Process each item with a goroutine and send output to sampleChan
    go newSample(line, *replicatePtr, *timePtr, sampleChan, &wg)
}

go func() {
    wg.Wait()
    close(sampleChan)
}()

for s := range sampleChan {
  ..
}

作为样式说明(并遵循 https://github.com/golang/go/wiki/CodeReviewComments#synchronous-functions ),如果 newSample 是一个简单的同步函数,它不采用 WaitGroup 和 channel ,并且简单地生成其结果。然后工作代码看起来像:

for i, line := range contents {
    wg.Add(1)
    go func(line string) {
        defer wg.Done()
        sampleChan <- newSample(line, *replicatePtr, *timePtr)
    }(line)
}

这使您的并发原语保持在一起,除了简化 newSample 并使其更易于测试之外,它还允许您查看并发情况,并直观地检查 wg .Done() 总是被调用。如果您想重构代码以使用固定数量的工作人员,那么您的更改都将是本地的。

关于go - 使用 goroutines 处理值并将结果收集到 slice 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46010836/

相关文章:

go - 所有的 goroutines 都睡着了——死锁! - - - - 错误

go - 当 channel 关闭时,以接收 channel 作为参数的 goroutines 是否停止?

go - 发送 channel 后Goroutine无法执行

performance - 在 golang 中,为什么当我使用缓冲(异步) channel 时我的程序运行速度变慢?

go - 如何在 MacOS 上制作 wxWidgets(使用 golang)重绘窗口?

angular - 在 Angular 中更改页面时表格不显示数据

python - 使用列表中的字符串进行切片分配

go - 如何将接口(interface) slice 更改为结构 slice

postgresql - 通过其pq.StringArray属性查询GORM数据库

arrays - 如何在 RUST 中逐字节比较 2 个不同的字符串文字