Go例程矩阵乘法错误
Go routines Matrix multiplication error
我正在使用 go 例程并行乘以矩阵。我得到的索引超出范围,但是当我 运行 相同的代码顺序时它起作用了。 (按顺序我的意思是评论走线)。我正在使用延迟,所以我不必等待我的例程结束,因为这将是最后一个调用
错误
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;
}
我看到两个问题:
- 您在
multiply
和 i
和 j
中有一个经典的闭包问题。
- 无法保证
matrix_c
会在 return 之前计算 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);
}()
}
}
当您 go func() { ... }()
时,匿名函数保留对 i
和 j
的引用,而不是 i
和 j
的实际值,所以当goroutine 执行,i
和 j
可以是 0 到 3 之间的任何值( 包含 )。这就是您所知道的错误的来源:i
或 j
是三个,因为 goroutine 在 after 循环完成后执行。最简单的解决方案是强制在正确的时间计算 i
和 j
:
go func(i, j int) {
matrix_c[i][j] = pmultiply(matrix_a, matrix_b, i, j)
}(i, j)
第二个问题是 goroutines 不一定会在你之前全部完成 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)
}
}
然后等待 returning:
wg.Wait()
return matrix_c
对评论的回应: defer
这样不行,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.
就是这样,它安排在执行离开周围函数时执行某些操作。 defer
与等待 threads/goroutines 没有任何关系,它也不知道延迟函数可能创建的 goroutines。
我正在使用 go 例程并行乘以矩阵。我得到的索引超出范围,但是当我 运行 相同的代码顺序时它起作用了。 (按顺序我的意思是评论走线)。我正在使用延迟,所以我不必等待我的例程结束,因为这将是最后一个调用
错误 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;
}
我看到两个问题:
- 您在
multiply
和i
和j
中有一个经典的闭包问题。 - 无法保证
matrix_c
会在 return 之前计算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);
}()
}
}
当您 go func() { ... }()
时,匿名函数保留对 i
和 j
的引用,而不是 i
和 j
的实际值,所以当goroutine 执行,i
和 j
可以是 0 到 3 之间的任何值( 包含 )。这就是您所知道的错误的来源:i
或 j
是三个,因为 goroutine 在 after 循环完成后执行。最简单的解决方案是强制在正确的时间计算 i
和 j
:
go func(i, j int) {
matrix_c[i][j] = pmultiply(matrix_a, matrix_b, i, j)
}(i, j)
第二个问题是 goroutines 不一定会在你之前全部完成 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)
}
}
然后等待 returning:
wg.Wait()
return matrix_c
对评论的回应: defer
这样不行,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.
就是这样,它安排在执行离开周围函数时执行某些操作。 defer
与等待 threads/goroutines 没有任何关系,它也不知道延迟函数可能创建的 goroutines。