侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

使用goroutine和channel实现并发数组求和

2025-12-11 / 0 评论 / 4 阅读

题目

使用goroutine和channel实现并发数组求和

信息

  • 类型:问答
  • 难度:⭐

考点

goroutine基础使用,channel通信,WaitGroup同步

快速回答

使用Go并发计算数组元素之和的核心步骤:

  1. 将数组拆分为多个子段
  2. 为每个子段启动goroutine进行局部求和
  3. 使用channel传递局部结果
  4. 用sync.WaitGroup等待所有goroutine完成
  5. 主goroutine收集并累加最终结果
## 解析

原理说明

Go并发模型基于CSP理论,通过goroutine实现轻量级线程,channel用于goroutine间通信。sync.WaitGroup提供简单的同步机制,确保主goroutine等待所有工作完成。

代码示例

package main

import (
    "fmt"
    "sync"
)

func sumWorker(nums []int, ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    sum := 0
    for _, num := range nums {
        sum += num
    }
    ch <- sum // 将局部和发送到channel
}

func main() {
    nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    ch := make(chan int)
    var wg sync.WaitGroup

    // 将数组拆分为2个子段
    wg.Add(2)
    go sumWorker(nums[:len(nums)/2], ch, &wg)
    go sumWorker(nums[len(nums)/2:], ch, &wg)

    // 启动收集结果的goroutine
    go func() {
        wg.Wait()
        close(ch) // 所有worker完成后关闭channel
    }()

    // 主goroutine收集结果
    total := 0
    for partialSum := range ch {
        total += partialSum
    }

    fmt.Println("总和:", total) // 输出: 总和: 55
}

最佳实践

  • 任务拆分:根据CPU核心数动态确定goroutine数量
  • 资源管理:使用defer wg.Done()确保计数器释放
  • 通道安全:由独立goroutine关闭channel,避免向已关闭channel发送数据
  • 错误处理:可增加错误通道(error channel)收集异常

常见错误

  • 死锁:忘记wg.Add()或未启动收集结果的goroutine
  • 竞态条件:多个goroutine同时写共享变量(本例使用channel避免)
  • 通道阻塞:未及时接收channel数据导致goroutine阻塞
  • 指针误用:传递WaitGroup时未使用指针导致副本问题

扩展知识

  • 工作池模式:使用buffered channel创建固定数量的worker
  • Context控制:添加超时和取消机制
  • 原子操作:sync/atomic包实现无锁累加(但channel方案更符合Go哲学)
  • 性能考量:任务拆分粒度影响性能,过小的任务会增加调度开销