使用 goroutine 和通道的“矩阵乘法”

当我使用 1 个 goroutine、2 个 goroutine、3 个等等时,我有一个大学项目来测试矩阵乘法的时间差。我必须使用渠道。我的问题是,无论我添加多少 goroutine,编译时间几乎总是相同的。也许有人能说出问题出在哪里。也许发送时间很长,并且一直在发送。代码如下


package main

import (

    "fmt"

    "math/rand"

    "time"

)

const length = 1000

var start time.Time

var rez [length][length]int

func main() {

    const threadlength = 1

    toCalcRow := make(chan []int)

    toCalcColumn := make(chan []int)

    dummy1 := make(chan int)

    dummy2 := make(chan int)

    var row [length + 1]int

    var column [length + 1]int

    var a [length][length]int

    var b [length][length]int

    for i := 0; i < length; i++ {

        for j := 0; j < length; j++ {

            a[i][j] = rand.Intn(10)

            b[i][j] = rand.Intn(10)

        }

    }

    for i := 0; i < threadlength; i++ {

        go Calc(toCalcRow, toCalcColumn, dummy1, dummy2)

    }

    start = time.Now()

    for i := 0; i < length; i++ {

        for j := 0; j < length; j++ {

            row[0] = i

            column[0] = j

            for k := 0; k < length; k++ {

                row[k+1] = a[i][j]

                column[k+1] = b[i][k]

            }

            rowSlices := make([]int, len(row))

            columnSlices := make([]int, len(column))

            copy(rowSlices, row[:])

            copy(columnSlices, column[:])

            toCalcRow <- rowSlices

            toCalcColumn <- columnSlices

        }

    }

    dummy1 <- -1

    for i := 0; i < length; i++ {

        for j := 0; j < length; j++ {

            fmt.Print(rez[i][j])

            fmt.Print(" ")

        }

        fmt.Println(" ")

    }

    <-dummy2

    close(toCalcRow)

    close(toCalcColumn)

    close(dummy1)

}

func Calc(chin1 <-chan []int, chin2 <-chan []int, dummy <-chan int, dummy1 chan<- int) {

loop:

    for {

        select {

        case row := <-chin1:

            column := <-chin2

            var sum [3]int

            sum[0] = row[0]

            sum[1] = column[0]

            for i := 1; i < len(row); i++ {

                sum[2] += row[i] * column[i]

            }


倚天杖
浏览 115回答 2
2回答

慕妹3146593

您看不到差异,因为准备数据以传递给 go 例程是您的瓶颈。它比执行计算更慢或一样快。传递行和列的副本不是一个好的策略。这正在扼杀表演。go 例程可以直接从只读输入矩阵中读取数据。这里没有可能的竞争条件。输出也一样。如果 go 例程计算行和列的乘积,它会将结果写入不同的单元格。这里也没有可能的竞争条件。要做的事情如下。定义一个包含两个字段的结构,一个用于行,一个用于要相乘的列。用所有可能的行和列组合填充缓冲通道,以从 (0,0) 乘到 (n-1,m-1)。go 例程使用通道中的结构,执行计算并将结果直接写入输出矩阵。然后,您还有一个 done 通道向主 go 例程发出计算已完成的信号。当 goroutine 完成对结构 (n-1,m-1) 的处理时,它会关闭 done 通道。编写完所有结构后,主 go 例程在 done 通道上等待。一旦完成通道关闭,它就会打印经过的时间。我们可以使用一个等待组来等待所有的 goroutine 终止他们的计算。然后,您可以从一个 goroutine 开始,并增加 goroutine 的数量,以查看处理时间的影响。见代码:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")type pair struct {&nbsp; &nbsp; row, col int}const length = 1000var start time.Timevar rez [length][length]intfunc main() {&nbsp; &nbsp; const threadlength = 1&nbsp; &nbsp; pairs := make(chan pair, 1000)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; var a [length][length]int&nbsp; &nbsp; var b [length][length]int&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a[i][j] = rand.Intn(10)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b[i][j] = rand.Intn(10)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; wg.Add(threadlength)&nbsp; &nbsp; for i := 0; i < threadlength; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go Calc(pairs, &a, &b, &rez, &wg)&nbsp; &nbsp; }&nbsp; &nbsp; start = time.Now()&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pairs <- pair{row: i, col: j}&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; close(pairs)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; elapsed := time.Since(start)&nbsp; &nbsp; fmt.Println("Binomial took ", elapsed)&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Print(rez[i][j])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Print(" ")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(" ")&nbsp; &nbsp; }}func Calc(pairs chan pair, a, b, rez *[length][length]int, wg *sync.WaitGroup) {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; pair, ok := <-pairs&nbsp; &nbsp; &nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; rez[pair.row][pair.col] = 0&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rez[pair.row][pair.col] += a[pair.row][i] * b[i][pair.col]&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()}

慕哥6287543

您的代码很难理解(调用变量 dummy1/dummy2 会让人感到困惑,特别是当它们在 中获得不同的名称时Calc)并且添加一些注释会使它更容易理解。首先是一个错误。在发送要计算的数据之后dummy1 <- -1,我相信您希望这会等待所有计算完成。但是,当您有多个 goroutine 时,情况不一定如此。通道将被其中一个 goroutine 耗尽,并打印出计时信息;其他 goroutine 仍将运行(并且可能尚未完成计算)。在时间方面,我怀疑您向 go 例程发送数据的方式会减慢速度;您发送行,然后发送列;因为通道没有缓冲,所以 goroutine 将在等待列时阻塞(切换回主 goroutine 以发送列)。这种来回会减慢你的 goroutines 获取数据的速度,并且可以很好地解释为什么添加额外的 goroutines 影响有限(如果你使用缓冲通道也会变得危险)。我已将您的代码(注意可能存在错误,而且远非完美!)重构为确实显示出差异的东西(在我的计算机上 1 goroutine = 10s; 5 = 7s):package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")const length = 1000var start time.Timevar rez [length][length]int// toMultiply will hold details of what the goroutine will be multiplying (one row and one column)type toMultiply struct {&nbsp; &nbsp; rowNo&nbsp; &nbsp; int&nbsp; &nbsp; columnNo int&nbsp; &nbsp; row&nbsp; &nbsp; &nbsp; []int&nbsp; &nbsp; column&nbsp; &nbsp;[]int}func main() {&nbsp; &nbsp; const noOfGoRoutines = 5&nbsp; &nbsp; // Build up a matrix of dimensions (length) x (length)&nbsp; &nbsp; var a [length][length]int&nbsp; &nbsp; var b [length][length]int&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a[i][j] = rand.Intn(10)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b[i][j] = rand.Intn(10)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Setup completed so start the clock...&nbsp; &nbsp; start = time.Now()&nbsp; &nbsp; // Start off threadlength go routines to multiply each row/column&nbsp; &nbsp; toCalc := make(chan toMultiply)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(noOfGoRoutines)&nbsp; &nbsp; for i := 0; i < noOfGoRoutines; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Calc(toCalc)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }&nbsp; &nbsp; // Begin the multiplication.&nbsp; &nbsp; start = time.Now()&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tm := toMultiply{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rowNo:&nbsp; &nbsp; i,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; columnNo: j,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; row:&nbsp; &nbsp; &nbsp; make([]int, length),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; column:&nbsp; &nbsp;make([]int, length),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < length; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tm.row[k] = a[i][j]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tm.column[k] = b[i][k]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toCalc <- tm&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // All of the data has been sent to the chanel; now we need to wait for all of the&nbsp; &nbsp; // goroutines to complete&nbsp; &nbsp; close(toCalc)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; fmt.Println("Binomial took ", time.Since(start))&nbsp; &nbsp; // The full result should be in tz&nbsp; &nbsp; for i := 0; i < length; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < length; j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //fmt.Print(rez[i][j])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //fmt.Print(" ")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; //fmt.Println(" ")&nbsp; &nbsp; }}// Calc - Multiply a row from one matrix with a column from anotherfunc Calc(toCalc <-chan toMultiply) {&nbsp; &nbsp; for tc := range toCalc {&nbsp; &nbsp; &nbsp; &nbsp; var result int&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < len(tc.row); i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result += tc.row[i] * tc.column[i]&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // warning - the below should work in this case but be careful writing to global variables from goroutines&nbsp; &nbsp; &nbsp; &nbsp; rez[tc.rowNo][tc.columnNo] = result&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go