Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)_第1頁
Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)_第2頁
Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)_第3頁
Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)_第4頁
Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第Go語言開發(fā)必知的一個內(nèi)存模型細節(jié)目錄引言內(nèi)存模型定義是什么happens-before是什么A不一定happens-beforeBGo語言中的happens-before定義GoChannel實例例子1例子2例子3例子4總結(jié)

引言

在日常工作中,如果我們能夠了解Go語言內(nèi)存模型,那會帶來非常大的作用。這樣在看一些極端情況,又或是變態(tài)面試題的時候,就能夠明白程序運行表現(xiàn)下的很多根本原因了。

當然,靠一篇普通文章講完Go內(nèi)存模型,不可能。因此今天這篇文章,把重點劃在給大家講解Go語言的happens-before原則這1個細節(jié)。

內(nèi)存模型定義是什么

既然要了解happens-before原則,我們得先知道TheGoMemoryModel(Go內(nèi)存模型)定義的是什么,官方解釋如下:

TheGomemorymodelspecifiestheconditionsunderwhichreadsofavariableinonegoroutinecanbeguaranteedtoobservevaluesproducedbywritestothesamevariableinadifferentgoroutine.

在Go內(nèi)存模型規(guī)定:在一個goroutine中讀取一個變量時,可以保證觀察到不同goroutine中對同一變量的寫入所產(chǎn)生的值的條件。

這是學習后續(xù)知識的一個大前提。

happens-before是什么

HappensBefore是一個專業(yè)術(shù)語,與Go語言沒有直接關(guān)系,也就是并非是特有的。用大白話來講,其定義是:

在一個多線程程序中,假設(shè)存在A和B兩個操作,如果A操作在B操作之前發(fā)生(Ahappens-beforeB),那么A操作對內(nèi)存的影響將會對執(zhí)行B的線程可見。

A不一定happens-beforeB

從happens-before定義來看,我們可以反過來想。那就是:

在同一個(相同)線程中,如果都執(zhí)行A和B操作,并且A的聲明一定在B之前,那么A一定先于(happens-before)B發(fā)生。

以下述Go代碼例子:

var

A

int

var

B

int

func

main()

{

A

=

B

+

1

(1)

B

=

1

(2)

}

該代碼是在同一個maingoroutine,全局變量A在變量B之前聲明。

在main函數(shù)中,代碼行(1),也在代碼行(2)之前。因此我們可以得出(1)一定會在(2)前執(zhí)行,對嗎?

答案是:錯誤的,因為Ahappens-beforeB并不意味著A操作一定會在B操作之前發(fā)生。

實際上在編譯器中,上述代碼在匯編的真正執(zhí)行順序如下:

0x0000

00000

(main.go:7)

MOVQ

"".B(SB),

AX

0x0007

00007

(main.go:7)

INCQ

AX

0x000a

00010

(main.go:7)

MOVQ

AX,

"".A(SB)

0x0011

00017

(main.go:8)

MOVQ

$1,

"".B(SB)

(2):加載B到寄存器AX。(2):進行B=1賦值,在代碼中執(zhí)行為INCQ自增。(1):將寄存器AX中值加上1后賦值給A。

通過上述分析,我們可以得知。在代碼行(1)在(2)之前,但確實(2)比(1)更早執(zhí)行。

那么這是不是意味著違反了happens-before的設(shè)計原則,畢竟這可是同個線程里的操作,Go編譯器有BUG?

其實不然,因為對A的賦值實質(zhì)上對B的賦值沒有影響。所以并沒有違反happens-before的設(shè)計原則。

Go語言中的happens-before

在《TheGoMemoryModel》中,給出了Go語言中HappensBefore的明確語言定義。

以下術(shù)語將會在介紹中用到:

變量v:一個指代性的變量,用于示例演示。讀r:代表讀操作。寫w:代表寫操作。

定義

在滿足如下兩點條件下,允許對變量v的讀r觀察對v的寫w:

r在w之前沒有發(fā)生。沒有其他寫到v的w發(fā)生在w之后但在r之前。

為了保證變量v的讀r觀察到對v的特定寫w,確保w是唯一允許r觀察的寫。

因此如果以下兩點都成立,就能保證r能觀察到w:

w發(fā)生在r之前。對共享變量v的任何其他寫入都發(fā)生在w之前或r之后。

這看起來比較生澀,接下來我們以《TheGoMemoryModel》中具體的channel例子來進行進一步說明,會更好理解一些。

GoChannel實例

在Go語言中提倡不要通過共享內(nèi)存來進行通訊;相反,應(yīng)當通過通訊來共享內(nèi)存:

Donotcommunicatebysharingmemory;instead,sharememorybycommunicating.

因此在Go工程中,Channel是一個非常常用的語法。在原則上其需要遵守:

一個channel上的發(fā)送是在該channel的相應(yīng)接收完成之前發(fā)生的。channel的關(guān)閉發(fā)生在接收之前,因為通道被關(guān)閉而返回一個零值。一個無緩沖channel的接收發(fā)生在該channel的發(fā)送完成之前。一個容量為C的channel上,第k次接收發(fā)生在該channel的第k+C次發(fā)送完成之前。

接下來根據(jù)這四條原則,我們逐一給出例子,用于學習和理解。

例子1

Gochannel例子1,你認為輸出的結(jié)果是什么。如下:

var

c

=

make(chan

int,

10)

var

a

string

func

f()

{

a

=

"炸煎魚"

(1)

c

-

0

(2)

func

main()

{

go

f()

-c

(3)

print(a)

(4)

}

答案是空字符串嗎?

程序最終結(jié)果是正常輸出炸煎魚的,原因如下:

(1)happens-before(2)。(4)happens-after(3)。

當然,最后(1)寫入變量a的操作,必然happens-before于(4)print方法,因此正確的輸出了炸煎魚。

能夠滿足一個channel上的發(fā)送是在該channel的相應(yīng)接收完成之前發(fā)生的。

例子2

主要是確保了關(guān)閉管道時的行為。只需要在前面的例子中,替換c-0成close(c)就能夠產(chǎn)生具有相同的行為保證的程序。

能夠滿足channel的關(guān)閉發(fā)生在接收之前,因為通道被關(guān)閉而返回一個零值。

例子3

Gochannel例子3,你認為輸出的結(jié)果是什么。如下:

var

c

=

make(chan

int)

var

a

string

func

f()

{

a

=

"煎魚進腦子了"

(1)

-c

(2)

func

main()

{

go

f()

c

-

0

(3)

print(a)

(4)

}

答案是空字符串嗎?

程序最終結(jié)果是正常輸出煎魚進腦子了的,原因如下:

(2)happens-before(3)。(1)happens-before(4)。

能夠滿足一個無緩沖channel的接收發(fā)生在該channel的發(fā)送完成之前。

如果我們把無緩沖改為make(chanint,1),也就是帶緩沖的channel,則無法保證正常的輸出煎魚進腦子了。

例子4

Gochannel例子4,這個程序為工作列表中的每個條目啟動一個goroutine,但goroutine使用channel進行協(xié)調(diào),以確保每次最多只有三個工作函數(shù)在運行。

代碼如下:

var

limit

=

make(chan

int,

3)

func

main()

{

for

_,

w

:=

range

work

{

go

func(w

func())

{

limit

-

1

w()

-limit

}(w)

select{}

}

能夠滿足一個容量為C的channel上,第k次接收發(fā)生在該channel的第k+C次發(fā)送完成之前。

總結(jié)

在本文中,我們針對happens-before原則進行了基本的說明。同時結(jié)合Go語言中實際的happens-before和happens-after的場景進了展示和講解。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論