栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

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

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

这是因为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, $0-8    0x0000 00000 (elide.go:7)   FUNCDATA    $0, gclocals·2a5305abe05176240e61b8620e19a815(SB)    0x0000 00000 (elide.go:7)   FUNCDATA    $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)    0x0000 00000 (elide.go:9)   JMP 0

对于编译器,

for {    i++}

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

for
循环)来实现。

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

goroutine扩展为

"".main.func1 STEXT size=81 args=0x8 locals=0x18    0x0000 00000 (elide.go:7)   TEXT    "".main.func1(SB), $24-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    $24, 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    $0, gclocals·a36216b97439c93dafebe03e7f0808b5(SB)    0x001d 00029 (elide.go:7)   FUNCDATA    $1, 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  $0, $0    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    $3, 8(SP)    0x003e 00062 (elide.go:10)  PCDATA  $0, $0    0x003e 00062 (elide.go:10)  CALL    runtime.printstring(SB)    0x0043 00067 (elide.go:10)  PCDATA  $0, $0    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  $0, $-1    0x004a 00074 (elide.go:7)   CALL    runtime.morestack_noctxt(SB)    0x004f 00079 (elide.go:7)   JMP 0

goroutine的增加的复杂性意味着编译器不再考虑将寄存器专用于的值

i
。内存中的值
i
会增加,这使得更新与数据竞争可见于
main
goroutine。

==================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()}

输出:

41807838


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/448099.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号