我有这段简单的代码(或https://play.golang.org/p/KW8_OHUp9v)
package main
import (
"fmt"
"sync"
)
func main() {
mutex := new(sync.Mutex)
for i := 1; i < 5; i++ {
for j := 1; j < 5; j++ {
mutex.Lock()
go func() {
fmt.Printf("%d + %d = %d\n", i, j, j+i)
mutex.Unlock()
}()
}
}
}
它产生这样的输出
1 + 2 = 3
1 + 3 = 4
1 + 4 = 5
2 + 5 = 7
2 + 2 = 4
2 + 3 = 5
2 + 4 = 6
3 + 5 = 8
3 + 2 = 5
3 + 3 = 6
3 + 4 = 7
4 + 5 = 9
4 + 2 = 6
4 + 3 = 7
4 + 4 = 8
Program exited.
看看输出我很惊讶:
j
j
我可以理解缺少'1',因为变量在写入之前会递增。
有人可以解释2.和3.?
答案 0 :(得分:3)
您正在关闭循环中的变量,然后在单独的线程中运行闭包,而这些变量会继续更改。当你这样做时,期望意外 - 例如,你看到5s因为j
在最后一次迭代时增加到5,这导致循环结束,但j
仍然保持5,这是单独的然后线程可以读取。它与你的互斥锁无关;它是变量的跨线程共享。如果您使用:
go func(i,j int) {
fmt.Printf("%d + %d = %d\n", i, j, j+i)
mutex.Unlock()
}(i,j)
然后它会在你的goroutine启动时传递i
和j
的值,后续迭代不会影响它:https://play.golang.org/p/P3kUP5e1Fp
答案 1 :(得分:1)
执行此操作时:
go func() {
fmt.Printf("%d + %d = %d\n", i, j, j+i)
mutex.Unlock()
}()
当前goroutine创建另一个循环,增加j。
增量发生在printf之前,这就是为什么即使认为函数被调用的原因
j
< 5
$(function() {
// prevent the submit button to be pressed twice
$(".createForm").submit(function() {
$(this).find('.submit').attr('disabled', true);
$(this).find('.submit').text('Sending, please wait...');
});
})
可以在函数有时间打印出值之前将其增加到5
换句话说,你的程序运行如下:
解决这个问题的方法是将值按值传递给函数,而不是在整个goroutine中共享它们。