You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中并发写入切片不同元素是否安全?

关于你的Go并发任务结果写入切片的安全性问题

你这段代码的操作完全是线程安全的,可以放心使用,原因如下:

  • 无数据竞争的切片访问:你在启动goroutine时,把循环的i和job都作为参数传递给了闭包,这意味着每个goroutine拿到的都是当前循环迭代的独立副本。每个goroutine只会写入results[i]这个唯一的索引位置,不存在多个goroutine同时修改同一个内存地址的情况,自然不会产生数据竞争。

    这里要给你点个赞——很多人容易犯的错误是直接在闭包里引用循环变量i,那样所有goroutine会共享同一个i变量,导致写入错误的索引位置,但你完美避开了这个坑!

  • WaitGroup的正确使用:你在每次启动goroutine前调用wg.Add(1),goroutine内部用defer wg.Done()确保无论任务成功还是失败(只要goroutine正常退出)都会减少计数,最后wg.Wait()会阻塞直到所有goroutine完成,保证你在后续使用results切片时,所有任务的结果都已经被正确写入。

额外的注意事项

虽然你的代码没问题,但还是提两个点帮你巩固:

  1. 确保doWork函数本身是线程安全的——如果doWork内部有共享变量或者其他并发操作,那你需要额外处理,但从代码看你只是传入job,只要job是值传递(或者你确保job在goroutine里不会被其他地方修改),就没问题。
  2. 你的results切片是提前分配好长度的,这非常合适。如果是用append来添加结果,那必须用互斥锁(比如sync.Mutex)保护,因为append可能会修改切片的底层数组和长度,多个goroutine同时append会导致数据竞争,但你这里直接按索引写入,完全不需要额外的同步机制。

举个反例,要是你没把i作为参数传入goroutine,错误代码会是这样:

// 错误示例!不要这么写!
for i, job := range jobs {
    wg.Add(1)
    go func() {
        defer wg.Done()
        results[i] = doWork(job) // 这里的i是循环的共享变量,会导致索引混乱
    }()
}

但你当前的写法完全规避了这个问题,所以可以放心使用。

内容的提问来源于stack exchange,提问作者captncraig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:19:57