Error[8]: Undefined offset: 25, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, [+++] 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA [+++], $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

[+++]

goroutine扩展为

[+++]

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值[+++]。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 26, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA [+++], $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

[+++]

goroutine扩展为

[+++]

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值[+++]。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 27, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

[+++]

goroutine扩展为

[+++]

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值[+++]。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 28, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

[+++]

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值[+++]。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 29, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值[+++]。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 30, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值[+++]会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 31, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值会增加,这使得更新与数据竞争可见于[+++]goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 32, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值会增加,这使得更新与数据竞争可见于goroutine。

[+++]

为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 33, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值会增加,这使得更新与数据竞争可见于goroutine。


为了获得预期的结果,请添加一些同步,

[+++]

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 34, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值会增加,这使得更新与数据竞争可见于goroutine。


为了获得预期的结果,请添加一些同步,

输出:

[+++]


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
这是因为go编译器优化了代码吗?_随笔_内存溢出

这是因为go编译器优化了代码吗?

这是因为go编译器优化了代码吗?,第1张

这是因为go编译器优化了代码吗?

记忆模型

2014年5月31日版本

介绍

Go内存模型指定了一种条件,在这种条件下,可以保证在一个goroutine中读取变量可以观察到在不同goroutine中写入同一变量所产生的值。

忠告

修改由多个goroutine同时访问的数据的程序必须序列化此类访问。

要序列化访问,请使用通道 *** 作或其他同步原语(例如sync和sync / atomic包中的原语)保护数据。

如果您必须阅读本文档的其余部分以了解程序的行为,那么您就太聪明了。

别聪明

同步化

var a stringfunc hello() {  go func() { a = "hello" }()  print(a)}

分配给a不会跟随任何同步事件,因此不能保证任何其他goroutine都会遵守它。实际上,积极的编译器可能会删除整个go语句。


i
通过增量
i++
i = i +1
)分配给时,没有任何同步事件,因此不能保证任何其他goroutine都会遵守该事件。实际上,积极的编译器可能会删除整个
i++
语句。

例如,

package mainimport "time"func main() {    i := 1    go func() {        for { i++        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

输出:

1

goroutine简化为:

"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), NOSPLIT, 
for {    i++}
-8 0x0000 00000 (elide.go:7) FUNCDATA
for
, gclocals·2a5305abe05176240e61b8620e19a815(SB) 0x0000 00000 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (elide.go:9) JMP 0

对于编译器,

for { }

可以通过永久增加一个寄存器(基本上是一个无 *** 作

print
循环)来实现。

package mainimport "time"func main() {    i := 1    go func() {        for { i++ println("+1")        }    }()    <-time.After(1 * time.Millisecond)    println(i)}

插入

+1+1<< SNIP >>+1+1432
语句后,

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), -8    0x0000 00000 (elide.go:7)   MOVQ    (TLS), CX    0x0009 00009 (elide.go:7)   CMPQ    SP, 16(CX)    0x000d 00013 (elide.go:7)   JLS 74    0x000f 00015 (elide.go:7)   SUBQ    , SP    0x0013 00019 (elide.go:7)   MOVQ    BP, 16(SP)    0x0018 00024 (elide.go:7)   LEAQ    16(SP), BP    0x001d 00029 (elide.go:7)   FUNCDATA    
i
, gclocals·a36216b97439c93dafebe03e7f0808b5(SB) 0x001d 00029 (elide.go:7) FUNCDATA , gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX 0x0022 00034 (elide.go:9) INCQ (AX) 0x0025 00037 (elide.go:10) PCDATA
i
,
main
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB) 0x002a 00042 (elide.go:10) LEAQ go.string."+1n"(SB), AX 0x0031 00049 (elide.go:10) MOVQ AX, (SP) 0x0035 00053 (elide.go:10) MOVQ , 8(SP) 0x003e 00062 (elide.go:10) PCDATA
==================WARNING: DATA RACERead at 0x00c420094000 by main goroutine:  main.main()      /home/peter/gopath/src/lucky.go:14 +0xacPrevious write at 0x00c420094000 by goroutine 5:  main.main.func1()      /home/peter/gopath/src/lucky.go:9 +0x4eGoroutine 5 (running) created at:  main.main()      /home/peter/gopath/src/lucky.go:7 +0x7a==================
,
package mainimport (    "sync"    "time")func main() {    mx := new(sync.Mutex)    i := 1    go func() {        for { mx.Lock() i++ mx.Unlock()        }    }()    <-time.After(1 * time.Second)    mx.Lock()    println(i)    mx.Unlock()}
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB) 0x0043 00067 (elide.go:10) PCDATA
41807838
, 0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB) 0x0048 00072 (elide.go:9) JMP 29 0x004a 00074 (elide.go:9) NOP 0x004a 00074 (elide.go:7) PCDATA , $-1 0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB) 0x004f 00079 (elide.go:7) JMP 0

输出:

goroutine扩展为

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值。内存中的值会增加,这使得更新与数据竞争可见于goroutine。


为了获得预期的结果,请添加一些同步,

输出:



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5170719.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-18
下一篇 2022-11-18

发表评论

登录后才能评论

评论列表(0条)

保存