本文概览: 获取协程返回结果;使用go func()正确姿势。
1 获取协程返回结果
1.1 举例1 【参考】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
func sum() (int64,error) { var wg sync.WaitGroup count := 10 resultChannel := make(chan int64, count) var err error // 1.并行处理 for index := 0; index < count; index++ { wg.Add(1) go func(i int) { defer wg.Done() num, sumErr := doSomething() resultChannel <- num // 将结果发送到结果通道中 if sumErr != nil { err = sumErr } }(index) } wg.Wait() <strong>close(resultChannel) // 关闭通道,表示数据发送完毕</strong> if err != nil { return 0, err } // 2.统计 var total int64 for oneCount := range resultChannel { total += oneCount } return total,nil } |
1.2 大模型返回的demo
问心一言:“golang 实现汇总多协程返回的结果”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package main import ( "fmt" "sync" ) func worker(wg *sync.WaitGroup, id int, results chan int) { defer wg.Done() sum := 0 for { // 从通道中接收数据 num, ok := <-data if !ok { break // 通道关闭,退出循环 } // 对数据进行处理或累加 sum += num } results <- sum // 将结果发送到结果通道中 } func main() { nums := []int{10, 20, 30, 40, 50} // 需要汇总的数据列表 data := make(chan int, len(nums)) // 用于传递数据的通道 results := make(chan int) // 用于汇总结果的通道 var wg sync.WaitGroup // 等待所有协程完成的等待组 // 将数据发送到通道中 for _, num := range nums { data <- num } close(data) // 关闭通道,表示数据发送完毕 // 启动协程进行数据处理和汇总 for i := 1; i <= 3; i++ { // 假设有3个协程进行数据处理和汇总 wg.Add(1) // 增加等待计数器 go worker(&wg, i, results) // 启动协程 } // 汇总结果并输出 go func() { var totalSum int for i := 1; i <= 3; i++ { // 假设有3个协程进行数据处理和汇总 sum := <-results // 从结果通道中接收结果 totalSum += sum // 累加结果 } fmt.Println("Total sum:", totalSum) wg.Done() // 完成汇总操作,减少等待计数器 }() wg.Wait() // 等待所有协程完成 fmt.Println("All goroutines have finished.") } |
2 go func()问题
1 2 3 4 5 6 7 8 9 10 11 12 |
var shardCount int64 shardCount = 2 var wg sync.WaitGroup for shardIndex := 0; shardIndex < int(shardCount); shardIndex++ { // 并行读每个shard wg.Add(1) go func() { defer wg.Done() fmt.Println("%d",<span style="color: #ff0000;"> int64(shardIndex))</span> }() } wg.Wait() |
上面代码有问题,在于并发访问shardIndex
变量,这会导致goroutine访问到同一个变量,结果输出的顺序可能与预期不符。
为了解决这个问题,可以将shardIndex
作为参数传递给goroutine,可以使用闭包技术将该变量复制给新的变量,
1 2 3 4 5 6 7 8 9 10 |
var shardCount int64 shardCount = 2var wg sync.WaitGroup var shardIndex intfor shardIndex := 0; shardIndex < int(shardCount); shardIndex++ { wg.Add(1) go func(<span style="color: #ff0000;">index int)</span> { defer wg.Done() fmt.Println(index) }<span style="color: #ff0000;">(shardIndex)</span> } wg.Wait() |
所以后续go func()正确姿势都可以这么写。
1 2 3 |
go func<span style="color: #ff0000;">(xx..</span>){ }(<span style="color: #ff0000;">aa</span>) |