英文:
Golang: writing to a variable has no effect in a goroutine if immediately followed by a `for{}` loop
问题
package main
import (
"fmt"
"time"
)
func main() {
var x = 0
go func() {
x = 1
for {
}
}()
time.Sleep(5000 * time.Millisecond)
fmt.Printf("%d", x)
}
为什么上面的代码会打印0
?
如果在for{}
之前或之中添加任何内容,例如runtime.Gosched()
,print(x)
,它将按预期打印1
。
这与写屏障/先行发生关系吗?我完全困惑了。
我让另一个goroutine在打印值之前休眠了5秒钟。这不足以让写操作同步/缓存刷新/...吗?
英文:
package main
import (
"fmt"
"time"
)
func main() {
var x = 0
go func() {
x = 1
for {
}
}()
time.Sleep(5000 * time.Millisecond)
fmt.Printf("%d", x)
}
Why does the above code print 0
?
If you add anything before or in the for{}
, for example, runtime.Gosched()
, print(x)
, it will print 1
as expected.
Is it related to write barrier / happened-before, or? I'm totally confused.
I made the other goroutine sleep for 5 seconds before printing the value. Isn't it enough time for the write to sync / cache to flush / ...?
答案1
得分: 3
感谢你的评论,Cerise。
~ go tool compile -S main.go
...
"".main.func1 STEXT nosplit size=3 args=0x0 locals=0x0 funcid=0x0
0x0000 00000 (main.go:10) TEXT "".main.func1(SB), NOSPLIT|NEEDCTXT|ABIInternal, $0-0
0x0000 00000 (main.go:10) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:10) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:12) XCHGL AX, AX
0x0001 00001 (main.go:1) JMP 0
0x0000 90 eb fd
看起来,Golang编译器确实在汇编代码中删除了x = 1
语句(应该是main.go:11
)。
在编程时,我们确实需要牢记《Go内存模型》和《Happens Before》的原则。
英文:
Thanks for the comment, Cerise.
~ go tool compile -S main.go
...
"".main.func1 STEXT nosplit size=3 args=0x0 locals=0x0 funcid=0x0
0x0000 00000 (main.go:10) TEXT "".main.func1(SB), NOSPLIT|NEEDCTXT|ABIInternal, $0-0
0x0000 00000 (main.go:10) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:10) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:12) XCHGL AX, AX
0x0001 00001 (main.go:1) JMP 0
0x0000 90 eb fd
Seems like golang compiler indeed deleted the x = 1
statement in the assembly (should be main.go:11
).
We really need to keep The Go Memory Model and Happens Before in mind when programming.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论