<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么會(huì)有atomic.LoadInt32

          共 2437字,需瀏覽 5分鐘

           ·

          2022-06-09 05:38

          前些天我們聊了 Golang 內(nèi)存對(duì)齊[1]的話題,后來(lái)我突然想到另一個(gè)問(wèn)題:為什么會(huì)有 atomic.LoadInt32[2]?可能你覺(jué)得思維太跳躍了,容我慢慢道來(lái):首先,有 atomic.LoadInt64[3] 很正常,因?yàn)閷?duì)一個(gè) int64 來(lái)說(shuō),它的大小是 8 個(gè)字節(jié),如果是 32 位平臺(tái)的話(字長(zhǎng) 4 字節(jié)),CPU 一次最多操作 4 個(gè)字節(jié),需要兩次才能拿到全部數(shù)據(jù),所以封裝一個(gè) atomic.LoadInt64 來(lái)實(shí)現(xiàn)原子操作;但是,對(duì)一個(gè) int32 數(shù)據(jù)來(lái)說(shuō),它的大小是 4 字節(jié),不管是 32 位平臺(tái)(字長(zhǎng) 4 字節(jié)),還是 64 位平臺(tái)(字長(zhǎng) 8 字節(jié)),CPU 應(yīng)該都可以保證一次操作拿到數(shù)據(jù),換句話說(shuō),如果讀取一個(gè) int32 數(shù)據(jù),那么本身就應(yīng)該是原子的,可是為什么會(huì)有 atomic.LoadInt32,這不是脫了褲子放屁么?

          有病沒(méi)病走兩步,讓我們寫一段代碼來(lái)驗(yàn)證一下:

          package?main

          import?"sync/atomic"

          var?v?=?int32(0)

          func?main()?{
          ?var?x?int32
          ?x?=?v?//?main.go:9
          ?_?=?x
          ?x?=?atomic.LoadInt32(&v)?//?main.go:11
          ?_?=?x
          }

          通過(guò)「go tool compile」運(yùn)行代碼,拿到對(duì)應(yīng)的匯編結(jié)果:

          shell>?go?tool?compile?-N?-l?-S?main.go

          0x0016?00022?(main.go:9)????????MOVL????"".v(SB),?AX
          0x001c?00028?(main.go:9)????????MOVL????AX,?"".t+4(SP)
          0x0020?00032?(main.go:11)???????MOVL????"".v(SB),?AX
          0x0026?00038?(main.go:11)???????MOVL????AX,?"".t+4(SP)

          不管是「x = v」還是「x = atomic.LoadInt32(&v)」,對(duì)應(yīng)的匯編結(jié)果一摸一樣。問(wèn)題越來(lái)越有趣了,讓我們看看是否能從 sync/atomic[4] 的源代碼中找到答案:

          Golang 代碼中只有函數(shù)聲明,實(shí)際上是使用匯編實(shí)現(xiàn)的:

          //?doc.go
          func?LoadInt32(addr?*int32)?(val?int32)

          //?asm.s
          TEXT?·LoadInt32(SB),NOSPLIT,$0
          ?JMP?runtime∕internal∕atomic·Load(SB)

          順著路徑,跳轉(zhuǎn)到 runtime/internal/atomic[5],會(huì)發(fā)現(xiàn)每個(gè)平臺(tái)都有獨(dú)立的 Load 實(shí)現(xiàn):

          在 amd64 平臺(tái),Load 是用 Golang 實(shí)現(xiàn)的,等價(jià)于直接讀?。?/p>

          func?Load(ptr?*uint32)?uint32?{
          ?return?*ptr
          }

          在 arm64 平臺(tái),Load 是用匯編實(shí)現(xiàn)的,并不是簡(jiǎn)單的一次操作:

          TEXT?·Load(SB),NOSPLIT,$0-12
          ?MOVD?ptr+0(FP),?R0
          ?LDARW?(R0),?R0
          ?MOVW?R0,?ret+8(FP)
          ?RET

          如上可見(jiàn),atomic.LoadInt32 之所以存在,是因?yàn)槟承┢脚_(tái)存在特殊性,所以我們需要封裝一個(gè)統(tǒng)一的操作,如此更有利于我們寫出平臺(tái)無(wú)關(guān)的代碼。

          本文僅討論了 atomic 的原子性[6],實(shí)際上它還保證了可見(jiàn)性[7],有序性[8],有興趣的朋友可以搜索內(nèi)存屏障相關(guān)內(nèi)容,這是一個(gè)很復(fù)雜的主題,我就不獻(xiàn)丑了,推薦閱讀:Golang Memory Model[9]。

          參考資料

          [1]

          Golang 內(nèi)存對(duì)齊: https://blog.huoding.com/2021/09/29/951

          [2]

          atomic.LoadInt32: https://pkg.go.dev/github.com/hslam/atomic#LoadInt32

          [3]

          atomic.LoadInt64: https://pkg.go.dev/github.com/hslam/atomic#LoadInt64

          [4]

          sync/atomic: https://github.com/golang/go/tree/master/src/sync/atomic

          [5]

          runtime/internal/atomic: https://github.com/golang/go/tree/master/src/runtime/internal/atomic

          [6]

          原子性: https://www.1024cores.net/home/lock-free-algorithms/so-what-is-a-memory-model-and-how-to-cook-it

          [7]

          可見(jiàn)性: https://www.1024cores.net/home/lock-free-algorithms/so-what-is-a-memory-model-and-how-to-cook-it/visibility

          [8]

          有序性: https://www.1024cores.net/home/lock-free-algorithms/so-what-is-a-memory-model-and-how-to-cook-it/ordering

          [9]

          Golang Memory Model: https://www.jianshu.com/p/1596e1d7c126



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù)?ebook?獲??;還可以回復(fù)「進(jìn)群」,和數(shù)萬(wàn) Gopher 交流學(xué)習(xí)。

          瀏覽 75
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产69精品久久久久久 | 手机在线免费AV | 青青操免费精品 | 少妇视频成人 | 污污污在线看 |