Golang中如何并行运行这段代码

Golang中如何并行运行这段代码 大家好, 我有以下代码:

num := 100;
for i1 := 0; i1 < num; i1++ {
	for i2 := 0; i2 < num; i2++ {
		for i3 := 0; i3 < num; i3++ {
			for i4 := 0; i4 < num; i4++ {
				// 主体代码
			}
		}
	}
}

如何以并行模式运行这段代码? 有什么想法可以提供帮助吗? 谢谢,

3 回复

谢谢,

更多关于Golang中如何并行运行这段代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


正文代码是否引用了循环变量 i1、… i4?那么你可以启动一个 Goroutine:

// 正文代码
go func(a int, b int, c int, d int) {
  // 执行某些操作
} (i1, i2, i3, i4) // 我们必须在这里捕获这些值!

但是,根据 num 的大小以及正文代码所执行的操作,这可能不是最佳方案。你将启动 num^4 个 goroutine,如果每个 goroutine 都使用某些有限的资源,你可能会使该资源过载。

在Go中并行运行嵌套循环的常见方法是使用goroutine和sync.WaitGroup。以下是几种实现方式:

方案1:并行最外层循环

package main

import (
    "sync"
)

func main() {
    num := 100
    var wg sync.WaitGroup
    
    for i1 := 0; i1 < num; i1++ {
        wg.Add(1)
        go func(i1 int) {
            defer wg.Done()
            for i2 := 0; i2 < num; i2++ {
                for i3 := 0; i3 < num; i3++ {
                    for i4 := 0; i4 < num; i4++ {
                        // 主体代码
                        _ = i1 + i2 + i3 + i4
                    }
                }
            }
        }(i1)
    }
    
    wg.Wait()
}

方案2:并行两个外层循环(使用工作池)

package main

import (
    "sync"
)

func main() {
    num := 100
    var wg sync.WaitGroup
    workerCount := 10 // 控制并发goroutine数量
    jobs := make(chan [2]int, num*num)
    
    // 启动worker
    for w := 0; w < workerCount; w++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobs {
                i1, i2 := job[0], job[1]
                for i3 := 0; i3 < num; i3++ {
                    for i4 := 0; i4 < num; i4++ {
                        // 主体代码
                        _ = i1 + i2 + i3 + i4
                    }
                }
            }
        }()
    }
    
    // 分发任务
    for i1 := 0; i1 < num; i1++ {
        for i2 := 0; i2 < num; i2++ {
            jobs <- [2]int{i1, i2}
        }
    }
    close(jobs)
    
    wg.Wait()
}

方案3:使用errgroup管理goroutine(需要错误处理时)

package main

import (
    "golang.org/x/sync/errgroup"
)

func main() {
    num := 100
    var g errgroup.Group
    
    for i1 := 0; i1 < num; i1++ {
        i1 := i1 // 创建局部变量副本
        g.Go(func() error {
            for i2 := 0; i2 < num; i2++ {
                for i3 := 0; i3 < num; i3++ {
                    for i4 := 0; i4 < num; i4++ {
                        // 主体代码
                        _ = i1 + i2 + i3 + i4
                    }
                }
            }
            return nil
        })
    }
    
    _ = g.Wait()
}

方案4:并行所有循环(激进并行化)

package main

import (
    "sync"
    "runtime"
)

func main() {
    num := 100
    var wg sync.WaitGroup
    sem := make(chan struct{}, runtime.NumCPU()*2) // 控制最大并发数
    
    for i1 := 0; i1 < num; i1++ {
        for i2 := 0; i2 < num; i2++ {
            for i3 := 0; i3 < num; i3++ {
                for i4 := 0; i4 < num; i4++ {
                    wg.Add(1)
                    sem <- struct{}{}
                    
                    go func(i1, i2, i3, i4 int) {
                        defer wg.Done()
                        defer func() { <-sem }()
                        
                        // 主体代码
                        _ = i1 + i2 + i3 + i4
                    }(i1, i2, i3, i4)
                }
            }
        }
    }
    
    wg.Wait()
}

关键注意事项:

  1. 闭包变量捕获:在goroutine中使用循环变量时,必须通过参数传递或创建局部副本
  2. 内存消耗:方案4会创建1亿个goroutine,通常不推荐
  3. 任务粒度:根据主体代码的执行时间选择合适的并行粒度
  4. 资源限制:使用缓冲通道或worker池控制并发数量

选择哪种方案取决于:

  • 主体代码的执行时间(CPU密集型还是I/O密集型)
  • 内存限制
  • 是否需要错误处理
  • 期望的并行度控制

对于大多数情况,方案1或方案2是最实用的选择。

回到顶部