I am multiplying matrix in parallel using go routines. I am getting index out of range, but when i run the same code sequential it works. (by sequential i mean commenting go line). I am using defer so i do not have to wait for my routines to end as it will be the last thing called
Error D:\0000>go run Ap.go panic: runtime error: index out of range
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
CODE
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;
}
I see two problems:
multiply
with i
and j
.matrix_c
will be computed before you return it in multiply
.The first one is right here:
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);
}()
}
}
The anonymous function is keeping a reference to i
and j
not the actual values of i
and j
when you go func() { ... }()
so when the goroutine executes, i
and j
could be any values between zero and three (inclusive). That's where the error you know about comes from: i
or j
is three because the goroutine is executing after the loops have completed. The easiest solution is to force i
and j
to be evaluated at the right time:
go func(i, j int) {
matrix_c[i][j] = pmultiply(matrix_a, matrix_b, i, j)
}(i, j)
The second problem is that the goroutines won't necessarily all finish before you return matrix_c
, there's not even a guarantee that any of of them will finish. The easiest solution would be to use a sync.WaitGroup
to wait for them to finish. First you'd import "sync"
, then adjust the loops:
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)
}
}
and then wait before returning:
wg.Wait()
return matrix_c
Response to Comments: defer
doesn't work like that, the specification only says:
A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.
That's it, it arranges for something to be executed when execution leaves the surrounding function. defer
doesn't have anything to do with waiting for threads/goroutines nor does it know anything about goroutines that the deferred function may create.