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

基于Go Routines优化无内置函数的矩阵乘法性能问询

Go协程实现矩阵乘法的优化方案

以下是你提供的矩阵乘法代码:

func main() {
    var wg sync.WaitGroup
    var col = 100
    var row = 150
    var randMatrixA [][]int
    var randMatrixB [][]int
    chA := make(chan [][]int)
    chB := make(chan [][]int)

    wg.Add(1)
    go genMat(row, col, chA, &wg)
    wg.Add(1)
    go genMat(col, row, chB, &wg)

    wg.Wait()

    randMatrixA = <-chA
    randMatrixB = <-chB
    fmt.Println(randMatrixA)

    fmt.Println(randMatrixB)

    fmt.Println("The Go Result of Matrix Multiplication = ")
    start := time.Now()
    c := doCalc(randMatrixA, randMatrixB)
    elapsed := time.Since(start)

    fmt.Println(c)

    fmt.Printf("Time taken to calculate %s \n", elapsed)
}
func genMat(row int, col int, ch chan<- [][]int, wg *sync.WaitGroup) {
    nM := make([][]int, col)
    for i := 0; i < col; i++ {
        nM[i] = make([]int, row)
    }
    generateNums(nM)
    wg.Done()
    ch <- nM
}
func generateNums(randMatrix [][]int) {
    for i, innerArray := range randMatrix {
        for j := range innerArray {
            randMatrix[i][j] = rand.Intn(100)
        }
    }
}
func rowCount(inM [][]int) int {
    return (len(inM))
}
func colCount(inM [][]int) int {
    return (len(inM[0]))
}
func doCalc(inA [][]int, inB [][]int) [][]int {
    var i, j int
    var wg sync.WaitGroup
    chC := make(chan [][]int)
    m := rowCount(inA) // number of rows the first matrix
    p := rowCount(inB) // number of rows the second matrix
    q := colCount(inB) // number of columns the second matrix
    k := 0
    total := 0
    var nM [][]int
    wg.Add(1)
    go genMat(m, q, chC, &wg)
    nM = <-chC
    wg.Wait()
    for i = 0; i < m; i++ {
        for j = 0; j < q; j++ {
            for k = 0; k < p; k++ {
                total = total + inA[i][k]*inB[k][j]
            }
            nM[i][j] = total
            total = 0
        }
        fmt.Println()
    }
    return nM
}

当前你通过两个协程并行生成矩阵A、B,单个协程计算结果矩阵C,平均耗时约2.4ms。以下是基于Go协程且不使用内置函数的优化建议,可将耗时降至1-2ms甚至更低:


优化建议

1. 并行化矩阵乘法核心计算

当前doCalc函数是单线程遍历计算结果矩阵,完全没利用多核CPU。可以将结果矩阵的每一行计算分配给独立协程,用sync.WaitGroup等待所有行计算完成,直接拉满计算效率。

修改后的doCalc示例:

func doCalc(inA [][]int, inB [][]int) [][]int {
    m := rowCount(inA)
    p := rowCount(inB)
    q := colCount(inB)
    // 直接初始化结果矩阵,无需额外协程
    nM := make([][]int, m)
    for i := range nM {
        nM[i] = make([]int, q)
    }

    var wg sync.WaitGroup
    wg.Add(m)
    for i := 0; i < m; i++ {
        // 启动协程计算第i行
        go func(i int) {
            defer wg.Done()
            rowA := inA[i] // 提前取出当前行,减少索引访问开销
            for j := 0; j < q; j++ {
                total := 0
                for k := 0; k < p; k++ {
                    total += rowA[k] * inB[k][j]
                }
                nM[i][j] = total
            }
        }(i) // 传递i的副本,避免循环变量引用问题
    }
    wg.Wait()
    return nM
}

2. 解决随机生成的并发锁竞争

rand.Intn不是并发安全的,多个协程调用时会触发内部互斥锁,拖慢矩阵生成速度。每个生成矩阵的协程应创建独立的随机源,完全避免锁开销:

修改generateNums函数:

func generateNums(randMatrix [][]int) {
    // 每个协程创建专属随机源
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    for i, innerArray := range randMatrix {
        for j := range innerArray {
            randMatrix[i][j] = r.Intn(100)
        }
    }
}

3. 移除不必要的IO与协程开销

原代码中的fmt.Println(randMatrixA)、fmt.Println(randMatrixB)以及doCalc里的fmt.Println()都是极耗时的IO操作,直接删除即可;同时doCalc中用协程初始化结果矩阵完全没必要,直接在函数内初始化,减少协程创建和通道通信的额外开销。

4. 优化内存布局提升缓存命中率

Go的二维切片是"切片的切片",内存地址不连续,访问时CPU缓存命中率低。可以改用一维数组模拟二维矩阵,通过索引计算定位元素,大幅提升缓存利用率:

修改后的doCalc(一维数组版本):

func doCalc(inA [][]int, inB [][]int) []int {
    m := rowCount(inA)
    p := rowCount(inB)
    q := colCount(inB)
    // 一维数组存储结果矩阵
    nM := make([]int, m*q)

    var wg sync.WaitGroup
    wg.Add(m)
    for i := 0; i < m; i++ {
        go func(i int) {
            defer wg.Done()
            rowA := inA[i]
            baseIdx := i * q // 当前行的起始索引
            for j := 0; j < q; j++ {
                total := 0
                for k := 0; k < p; k++ {
                    total += rowA[k] * inB[k][j]
                }
                nM[baseIdx+j] = total
            }
        }(i)
    }
    wg.Wait()
    return nM
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:34:59