go version)?$ go version go version go1.13.5 linux/amd64
yes
go env)?go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN="/home/me/go/bin"
GOCACHE="/home/me/.cache/go-build"
GOENV="/home/me/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/me/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build161703294=/tmp/go-build -gno-record-gcc-switches"
run following go script and get different output with and without the comment line
package main
import (
"fmt"
"time"
)
func main() {
var i = 0
go func() {
for {
i += 1
// time.Sleep(1*time.Nanosecond) <- this comment line
}
}()
for {
fmt.Println("i is", i)
time.Sleep(time.Second)
}
}
with the comment line I get
$ go run main.go
i is 0
i is 3673005
i is 7360961
i is 11182533
i is 14892563
i is 18696280
i is 21821713
....
but strangely, without that comment line I get:
$ go run main.go
i is 0
i is 0
i is 0
i is 0
i is 0
i is 0
....
with and without the comment line I get different assemble code:
assemble code shown below include the anonymous function run by go routine only.
without that comment line:
....
TEXT main.main.func1(SB) /home/me/go/src/github.com/trainyao/test/main.go
for {
0x48d0c0 eb00 JMP 0x48d0c2
i += 1
0x48d0c2 eb00 JMP 0x48d0c4
0x48d0c4 eb00 JMP 0x48d0c6
0x48d0c6 ebfa JMP 0x48d0c2
.....
with that comment line:
...
TEXT main.main.func1(SB) /home/me/go/src/github.com/trainyao/test/main.go
go func() {
0x48d0c0 64488b0c25f8ffffff MOVQ FS:0xfffffff8, CX
0x48d0c9 483b6110 CMPQ 0x10(CX), SP
0x48d0cd 7636 JBE 0x48d105
0x48d0cf 4883ec10 SUBQ $0x10, SP
0x48d0d3 48896c2408 MOVQ BP, 0x8(SP)
0x48d0d8 488d6c2408 LEAQ 0x8(SP), BP
for {
0x48d0dd eb00 JMP 0x48d0df
i += 1
0x48d0df eb00 JMP 0x48d0e1
0x48d0e1 488b442418 MOVQ 0x18(SP), AX
0x48d0e6 488b00 MOVQ 0(AX), AX
0x48d0e9 488b4c2418 MOVQ 0x18(SP), CX
0x48d0ee 48ffc0 INCQ AX
0x48d0f1 488901 MOVQ AX, 0(CX)
time.Sleep(1*time.Nanosecond)
0x48d0f4 48c7042401000000 MOVQ $0x1, 0(SP)
0x48d0fc e8df71fbff CALL time.Sleep(SB)
0x48d101 eb00 JMP 0x48d103
i += 1
0x48d103 ebda JMP 0x48d0df
go func() {
0x48d105 e8f646fcff CALL runtime.morestack_noctxt(SB)
0x48d10a ebb4 JMP main.main.func1(SB)
...
it seems like go complier ignore that i+=1 when complie into assemble code, and make that i+=1 do nothing.
command I use to generate assemble code:
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --gcflags "-N -l" -o main main.go
$ go tool objdump -S main > main.S
output of main.go is the same, with and without that comment line
different output
This problem also happens on go version go1.13.4 linux/amd64.
package main
import (
"fmt"
"time"
)
func main() {
var i, j int
noop := func() {}
onlyAdd := func() {
fmt.Println("onlyAdd runs")
for {
i += 1
}
}
notOnlyAdd := func() {
fmt.Println("notOnlyAdd runs")
for {
j += 1
noop()
}
}
go onlyAdd()
go notOnlyAdd()
for {
fmt.Println("i is", i, " and j is", j)
time.Sleep(time.Second)
}
}
output:
i is 0 and j is 0
onlyAdd runs
notOnlyAdd runs
i is 0 and j is 715125111
i is 0 and j is 1433046851
i is 0 and j is 2154902962
i is 0 and j is 2877082636
i is 0 and j is 3599230418
i is 0 and j is 4319943058
i is 0 and j is 5041545338
i is 0 and j is 5758950518
^C
Same issue on macos on go1.13.4 darwin/amd64.
i is 0 and j is 0
onlyAdd runs
notOnlyAdd runs
i is 0 and j is 800290823
i is 0 and j is 1604651414
i is 0 and j is 2395110243
i is 0 and j is 3187198741
i is 0 and j is 3971968750
i is 0 and j is 4752123974
...
You have a data race. You can see it if you do go run -race main.go, or if you read https://golang.org/doc/articles/race_detector.html.
You should use https://golang.org/wiki/Questions for general questions about why your code doesn't work.
if use go run -race main.go,
it output
i is 53406210
i is 106633590
i is 160145249
i is 213722371
i is 266922550
it looks like the race tool affected the code?
You have a data race. You can see it if you do
go run -race main.go, or if you read https://golang.org/doc/articles/race_detector.html.You should use https://golang.org/wiki/Questions for general questions about why your code doesn't work.
I know there is a data race in the code, but a data race would not make the for loop not adding i variable right? and how to explain the assemble code generated....will data race effect code compile? @mvdan
for {
i += 1
}
This is an infinite loop with no synchronization. No other thread is guaranteed to ever see the increment (because that would be a data race, and behavior under data races is undefined), so the compiler optimizes it away.
Most helpful comment
This is an infinite loop with no synchronization. No other thread is guaranteed to ever see the increment (because that would be a data race, and behavior under data races is undefined), so the compiler optimizes it away.