0

0

如何在 Go 中高效实现数组元素的并发处理

聖光之護

聖光之護

发布时间:2026-01-06 16:59:39

|

836人浏览过

|

来源于php中文网

原创

如何在 Go 中高效实现数组元素的并发处理

本文介绍如何使用 goroutine 和 sync.waitgroup 替代错误的通道切片方案,安全、简洁地实现整数切片的并发计算(如 `double` 函数),避免闭包变量捕获和索引越界问题,并确保结果顺序与输入一致。

在 Go 中实现切片元素的并发处理时,核心目标是:每个元素独立启动 goroutine 执行耗时操作(如 double(i)),所有 goroutine 并行运行,主协程等待全部完成后再统一返回有序结果。原代码中尝试用 []chan int 存储通道并手动索引赋值,但存在两个关键错误:

  1. 切片未初始化即索引访问:var chans []chan int 声明的是 nil 切片,长度为 0,直接执行 chans[i] = ... 必然 panic;
  2. 闭包变量捕获陷阱:for 循环中启动的匿名函数若直接引用循环变量 counter 和 number,由于 goroutine 启动异步且循环快速结束,所有 goroutine 实际共享同一组变量快照,导致数据竞争与错误索引(如全部写入 outArr[len(arr)-1])。

✅ 正确解法是:预分配结果切片 + sync.WaitGroup 同步 + 显式传参避免闭包捕获。以下是优化后的完整实现:

package main

import (
    "fmt"
    "sync"
    "time"
)

func double(i int) int {
    result := 2 * i
    fmt.Printf("double(%d) = %d\n", i, result)
    time.Sleep(500 * time.Millisecond) // 更清晰的写法
    return result
}

func notParallel(arr []int) []int {
    outArr := make([]int, 0, len(arr))
    for _, i := range arr {
        outArr = append(outArr, double(i))
    }
    return outArr
}

func parallel(arr []int) []int {
    n := len(arr)
    outArr := make([]int, n) // 预分配,保证顺序和容量
    var wg sync.WaitGroup

    for i, num := range arr {
        wg.Add(1)
        // 显式将 i 和 num 作为参数传入 goroutine,避免闭包捕获
        go func(index int, value int) {
            defer wg.Done()
            outArr[index] = double(value)
        }(i, num)
    }

    wg.Wait() // 阻塞直到所有 goroutine 完成
    return outArr
}

func main() {
    arr := []int{7, 8, 9}
    fmt.Println("串行执行:")
    fmt.Printf("结果: %v\n", notParallel(arr))

    fmt.Println("\n并发执行:")
    fmt.Printf("结果: %v\n", parallel(arr))
}

? 关键要点说明

PodLM
PodLM

PodLM是一款强大的AI播客生成工具

下载
  • 无需通道切片:本场景只需收集确定数量的结果且顺序固定,直接写入预分配切片比管理多个通道更高效、简洁;
  • sync.WaitGroup 是同步基石:Add() 标记任务数,Done() 在每个 goroutine 结束时调用,Wait() 阻塞主协程直至全部完成;
  • 闭包参数传递是必须实践:go func(i, v int) { ... }(i, num) 确保每个 goroutine 拥有自己独立的索引和值副本;
  • 预分配切片提升性能与安全性:make([]int, len(arr)) 避免 append 的动态扩容,同时保证 outArr[i] 索引合法;
  • 注意 double 的副作用:fmt.Println 在并发下输出可能乱序(因 goroutine 调度不确定性),但最终返回的 outArr 顺序严格与输入一致。

? 扩展建议:若需处理不确定数量或流式数据,或需错误传播、超时控制,则应选用带缓冲的通道(如 chan Result)配合 select 和 context,但对固定切片的映射类操作,WaitGroup + 预分配切片 是最轻量、最直观的并发模式。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

531

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

51

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

193

2025.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

51

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

98

2025.10.23

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

133

2025.07.29

go语言 数组和切片
go语言 数组和切片

本专题整合了go语言数组和切片的区别与含义,阅读专题下面的文章了解更多详细内容。

46

2025.09.03

php学习网站大全
php学习网站大全

精选多个优质PHP入门学习网站,涵盖教程、实战与文档,适合零基础到进阶开发者,助你高效掌握PHP编程。

0

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.5万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号