Перейти подпрограммы Ошибка умножения матрицы - PullRequest
0 голосов
/ 06 мая 2018

Я умножаю матрицу параллельно, используя процедуры go. Я получаю индекс вне диапазона, но когда я запускаю тот же самый последовательный код, он работает. (Под последовательным я подразумеваю комментирование иди). Я использую defer, поэтому мне не нужно ждать окончания моих подпрограмм, так как это будет последнее, что называется

Ошибка D: \ 0000> иди беги Ap.go паника: ошибка во время выполнения: индекс выходит за пределы диапазона

goroutine 5 [running]:
main.pmultiply(0xc04206c000, 0x3, 0x3, 0xc04206c050, 0x3, 0x3, 0x1, 0x3, 0x0)
        D:/0000/Ap.go:48 +0x95
main.multiply.func1(0xc04206c0a0, 0x3, 0x3, 0xc04200e090, 0xc04200e098, 0xc04206
c000, 0x3, 0x3, 0xc04206c050, 0x3, ...)
        D:/0000/Ap.go:64 +0x94
created by main.multiply
        D:/0000/Ap.go:63 +0x1d7
exit status 2

код

package main

import "fmt"

func main(){

    matrix_a := make([][]int,3);

    for i:=0;i<len(matrix_a);i++{

        matrix_a[i]=make([]int,3);

    }


    for i:=0;i<len(matrix_a);i++{

        for j:=0;j<len(matrix_a[0]);j++{
            matrix_a[i][j] = 2;
        }
    }

    matrix_b := make([][]int,3);

    for i:=0;i<len(matrix_b);i++{

        matrix_b[i]=make([]int,3);

    }


    for i:=0;i<len(matrix_b);i++{

        for j:=0;j<len(matrix_b[0]);j++{
            matrix_b[i][j] = 2;
        }
    }

    defer fmt.Println(multiply(matrix_a,matrix_b));

}

func pmultiply(matrix_a [][] int,matrix_b [][] int,row int,col int) int{

    sum := 0;

    for z:=0;z<len(matrix_a[0]);z++{
        sum = sum + matrix_a[row][z] *  matrix_b[z][col];
    }
    return sum;
}

func multiply(matrix_a [][] int,matrix_b [][] int) ([][] int){

    matrix_c := make([][]int,3);

    for i:=0;i<len(matrix_c);i++{
        matrix_c[i]=make([]int,3);
    }

    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            go func(){
                matrix_c[i][j] = pmultiply(matrix_a,matrix_b,i,j);
            }()
        }   
    }

    return matrix_c;
}

1 Ответ

0 голосов
/ 06 мая 2018

Я вижу две проблемы:

  1. У вас есть классическая проблема закрытия в multiply с i и j.
  2. Нет гарантии, что matrix_c будет вычислено до того, как вы вернете его в multiply.

Первый прямо здесь:

for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        go func(){
            matrix_c[i][j] = pmultiply(matrix_a,matrix_b,i,j);
        }()
    }   
}

Анонимная функция сохраняет ссылку на i и j, а не на фактические значения i и j, когда вы go func() { ... }(), поэтому при выполнении goroutine i и j могут быть любые значения от нуля до трех ( включительно ). Вот откуда возникает ошибка, о которой вы знаете: i или j - три, потому что программа выполняет после циклов. Самое простое решение - заставить i и j быть оцененными в нужное время:

go func(i, j int) {
    matrix_c[i][j] = pmultiply(matrix_a, matrix_b, i, j)
}(i, j)

Вторая проблема заключается в том, что не всегда все финишные функции завершатся перед вами return matrix_c, нет даже гарантии, что любой из них завершит работу. Самое простое решение - использовать sync.WaitGroup, чтобы дождаться их завершения. Сначала вы должны import "sync", а затем настроить петли:

var wg sync.WaitGroup
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        wg.Add(1) // Tell the WaitGroup to wait for another thing.
        go func(i, j int) {
            matrix_c[i][j] = pmultiply(matrix_a, matrix_b, i, j)
            wg.Done() // Tell it that we're done.
        }(i, j)
    }
}

, а затем подождите, прежде чем вернуться:

wg.Wait()
return matrix_c

Ответ на комментарии: defer не работает так, спецификация гласит только :

Оператор "defer" вызывает функцию, выполнение которой откладывается до момента, когда окружающая функция возвращается, либо потому, что окружающая функция выполнила оператор return, достигла конца своего тела функции, либо потому, что соответствующая процедура запаниковала.

Вот и все, он организует выполнение чего-либо, когда выполнение покидает окружающую функцию. defer не имеет ничего общего с ожиданием потоков / программ и не знает ничего о программах, которые может создать отложенная функция.

...