




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、引言先拋開你所熟知的信號量、鎖、同步原語等技術(shù),思考這個問題:如何保證并發(fā) 讀寫的準確性? 一個沒有任何并發(fā)編程經(jīng)驗的程序員可能會覺得很簡單:這有什 么問題呢,同時讀寫能有什么問題,最多就是讀到過期的數(shù)據(jù)而已。一個理想的 世界當然是這樣,只可惜實際上的機器世界往往隱藏了很多不容易被發(fā)覺的事情。 至少有兩個行為會影響這個結(jié)論:編譯器往往有指令重排序的優(yōu)化;例如程序員看到的源代碼是好句以4;,而實際上執(zhí)行的順序可能是以4;好3;,這是因為編譯器為了優(yōu)化執(zhí)行效 率可能對指令進行重排序; 高級編程語言所支持的運算往往不是原子化的;例如a += 3實際上包含了讀變量、加運算和寫變量三次原子操作。既然整個
2、過程并不是原子化的,就意味著隨時有其它入侵者侵入修改數(shù)據(jù)。更為隱藏的例子:對于變量 的讀寫甚至可能都不是原子化的。不同機器讀寫變量的過程可能是不同的, 有些機器可能是64位數(shù)據(jù)一次性讀寫,而有些機器是32位數(shù)據(jù)一次讀寫。這就意味著一個64位的數(shù)據(jù)在后者的讀寫上實際上是分成兩次完成的!試想,如果你試圖讀取一個64位數(shù)據(jù)的值,先讀取了低32的數(shù)據(jù),這時另一個線程切進來修改了整個數(shù)據(jù)的值,最后你再讀取高32的值,將高32和低32的數(shù)據(jù)拼成完整的值,很明顯會得到一個預期以外的數(shù) 據(jù)??雌饋?,整個并發(fā)編程的世界里一切都是不確定的,我們不知道每次讀取的變量 到底是不是及時、準確的數(shù)據(jù)。幸運的是,很多語言都
3、有一個kappehs-before的 規(guī)那么,能幫助我們在不確定的并發(fā)世界里尋找一絲確定性。happens-before你可以把ka叩看作一種特殊的比擬運算,就好像、一樣。對應(yīng)的,還有happe八s-aftec它們之間的關(guān)系也好像、一樣:Oncesync中還提供了一個。八cc的數(shù)據(jù)結(jié)構(gòu),用于控制并發(fā)編程中只執(zhí)行一次的邏輯,例如:var a striigvair oince sg八八ccfeme setapO (a = kelloj world11認土仇(set up11)fiAM do”int() o 八 ce.Do(s 血?)fmt.Prmtfn(a)Mac twopsMt。go dopHn
4、t。go dopHht。)會打印 hello, world”兩次和“set up”一次。八”的happens-be- 規(guī)那么也很直觀:第一次執(zhí)行。八ccQo happen-before其余的。八ceQo應(yīng)用掌握了上述的基本k即ins-bcf”c規(guī)那么,可以結(jié)合起來分析更復雜的場景了,來 看這個例子:var a, b Mtfeme f() a = 1 / (I)b = 2/ (2)心八cgO print(b) / priit(a) / (4)fiAAC kvaii0 go K)gO)這里ka眸ChS-befC (2),ka叩c八s-bcf”c(4),但是與、之間以及與 (3)、(4)之間并沒有k
5、appc八s-bcf”c關(guān)系,這時候結(jié)果是不確定的,一種有趣的結(jié) 果是2、0,也就是(1)、(2)之間發(fā)生了指令重排序?,F(xiàn)在讓我們修改一下上面的 代碼,讓它按我們預期的邏輯運行:要么打印0、0,要么打印1、2o使用鎖var a, b litvar lock Mutexfeme f()lock.LockQ / (2)4二工(2)b = 2 / lock.Unlock() / (4)心八c gO lock.LockO / priit(b) / (6)print / (7)(ock.Un(ock() / (8)八c kvxaiiaQ go fogO)回想下鎖的規(guī)那么:1.對鎖實例調(diào)用八次Unlock
6、 happ。八s-bcf。匕調(diào)用Lock作次,只要八這里,存在兩種可能:要么(4) happens-before,要么happen -before,會分 別推導出兩種結(jié)果: happe八s-bcfc (7) happens-before (2) happens-before (3), 以及(2) happe八s-before happens-befove (6) kappe八s-before (7),也就分別對應(yīng)“0、 0和 1、2兩種結(jié)果。使用通道 var a, b ivtvar c = iake(cka ict, 1) feme f() -c4 = 1(2)。= 2 / c一1)心八c g
7、O -cprint(b) / (6)priit(a) / (7)c b是否成立的過程,我們的做法很簡單:.基于一些簡單的公理;例如自然數(shù)的自然大小:/2工.基于比擬運算符的傳遞性,也就是如果。泌且分c,那么ac判斷a happen-before b的過程也是類似的:根據(jù)一些簡單的明確的happens-before 關(guān)系,再結(jié)合ka曄的傳遞性,推導出我們所關(guān)心的W和r之間的 kappens-before 關(guān)系。happc八s-before 傳遞性:如果 a happe八s-befoK。b,且 b happe八s-before C, 貝lj a happe八s-bef。丫。C因此我們只需要了解這些
8、明確的ha叩加關(guān)系,就能在并發(fā)世界里尋找到 珍貴確實定性了。go語言中的happens-before關(guān)系具體的happens-before關(guān)系是因語言而異的,這里只介紹go語言相關(guān)的規(guī)那么, 感興趣可以直接閱讀官方文檔,有更完整、準確的說明。自然執(zhí)行首先,最簡單也是最直觀的人即pens-before規(guī)那么:在同一個goroutine里,書寫在前的代碼happe八s-before書寫在后 的代碼。例如:a = 3; / (圾=4; / (2)那么Q) kappcns-bcforc (2)。我們上面提到指令重排序,也就是實際執(zhí)行的順序與書 寫的順序可能不一致,但h叩pens-before與指令重排
9、序并不矛盾,即使可能發(fā) 生指令重排序,我們依然可以說(1) happens-before (2)。初始化每個g。文件都可以有一個加土方法,用于執(zhí)行某些初始化邏輯。當我們開始執(zhí) 行某個小川認方法時,go會先在一個goroutine里做初始化工作,也就是執(zhí)行所 有g(shù)o文件的i八江方法,這個過程中g(shù)o可能創(chuàng)立多個goroutine并發(fā)地執(zhí)行,因此通常情況下各個知t方法是沒有人叩飛八s-before關(guān)系的。關(guān)于,八才方法有兩條happe八s-before 規(guī)那么:.a包導入了 b包,此時b包的iiit方法happe八s-before 3包的所有代碼;.所有iiit方法happe八s-before恒/認
10、方法;goroutinegoroutine相關(guān)的規(guī)那么主要是其創(chuàng)立和銷毀的:.goroutine 的創(chuàng)立 happens-砥。丫。其執(zhí)行;.goroutine的完成不保證k叩.八s-befo%任何代碼;第一條規(guī)那么舉個簡單的例子即可:var a stringface f() / (工)feme kelloQ a = heH。, world / (2)go f() )因為goroutine的創(chuàng)立happe八s-before其執(zhí)行,所以happe八s-before (1),又因為自然執(zhí)行的規(guī)那么(2) happe八s-before,根據(jù)傳遞性,所以happens-before (1),這樣保證了我
11、們每次打印出來的都是“hello world”而不是空字符串。第二條規(guī)那么是少見的否認句式,同樣舉個簡單的例子: fu 八c kelloQ go 4 二keo |() / (工)仇力八土伉(a) / (2)由于goroutine的完成不保證happens-before任何代碼,因此(1) happens-before不成立,這樣我們就不能保證每次打印的結(jié)果都是“hell?!?。通道通道channel是go語言中用于goroutine之間通信的主要渠道,因此理解通道 之間的happens-before規(guī)那么也至關(guān)重要。1 .對于緩沖通道,向通道發(fā)送數(shù)據(jù) 叱吟-砥。匕從通道接收到數(shù)據(jù)結(jié)合一個例子:v
12、ar c =八 int, LO)vair a string fuM f() a = helloj world / (1)C - O / (2)go fo / -c / (4)/ (5)c是一個緩沖通道,因此向通道發(fā)送數(shù)據(jù)ka叩ChS-befc從通道接收到數(shù)據(jù),也就 是happen-More (4),再結(jié)合自然執(zhí)行規(guī)那么以及傳遞性不難推導出Q) happens-before (5),也就是打印的結(jié)果保證是hello world。有趣的是,如果我們把C的定義改為var c =3砥左加血)也就是無緩沖通道,上 面的結(jié)論就不存在了(注1),打印的結(jié)果不一定為“hello world”,這是因為:.對于
13、無緩沖通道,從通道接收數(shù)據(jù)-before向通道發(fā)送數(shù) 據(jù)我們可以將上述例子稍微調(diào)整下:var c = kvake(cha a sWMgfeme f() a = heH。,world11 / (2)-c / (2)flAiaCgo f。c w := range work go ftmc。)limit - 1 / (1)w。 (2)/ Kw)select我們先套用一下上面的規(guī)那么,貝IJ:第1次第4次、第2次 (3)kappeias-before第5次、第3次happcns-before第6次,再結(jié)合傳遞性:”第 1 次(2)ka叩cns-befoHC 第 1 次happens-before 第
14、4 次Q)kappc八s-bcforc 第 4 次、第 2 次(2)happens -before 第 2 次happens -before 第 5 次 (l)kappens-before 第 5 次(2)”,簡單地說:第 1 次happens-before 第 4 次、”第2次(2)哂加* 第5次、第3次(2於-before第6次”這樣 我們雖然沒有做任何分批,卻事實上將workers分成三個一批、每批并發(fā)地執(zhí)行。 這就是通過這條happens-before規(guī)那么保證的。這個規(guī)那么理解起來其實也很簡單,C是通道的容量,如果無法保證第k次接收 happens-before第k+C次發(fā)送,那通道
15、的緩沖就不夠用了。注1:以上是官方文檔給的規(guī)那么和例子,但是筆者在嘗試將第一個 例子的c改成無緩沖通道后發(fā)現(xiàn)每次打印的依然穩(wěn)定是hell。world,并沒有出現(xiàn)預期的空字符串,也就是看起來happens-before 規(guī)那么依然成立。但既然官方文檔說無法保證,那我們開發(fā)時還是按 照happens-before不成立比擬好。鎖鎖也是并發(fā)編程里非常常用的一個數(shù)據(jù)結(jié)構(gòu)。go語言中支持的鎖主要有兩種: sgnc.Mutcx和sg八c.RWMutex,即普通鎖和讀寫鎖(讀寫鎖的原理可以參見另一篇文 章)。普通鎖的happens-before規(guī)那么也很直觀:1.對鎖實例調(diào)用八次Unlock happen-before調(diào)用Lock m次,只要八請看這個例子:var I yic.Mutexvair a string fimc f() a = hello,world11 / (1)I.UnlockQ / (2)fix八。加加八0 LLock。 / go f()/ (4)I.LockQ / priit(a
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 西安交通工程學院《口腔病理學》2023-2024學年第二學期期末試卷
- 西安職業(yè)技術(shù)學院《工管運籌學》2023-2024學年第二學期期末試卷
- 2025河北省安全員C證考試題庫
- 云南中醫(yī)藥大學《農(nóng)業(yè)推廣學》2023-2024學年第二學期期末試卷
- 遼寧特殊教育師范高等??茖W?!妒覂?nèi)專題項目生態(tài)性居住空間設(shè)計》2023-2024學年第二學期期末試卷
- 2025年江西省建筑安全員-A證考試題庫附答案
- 銅仁幼兒師范高等??茖W?!犊谇唤M織病理學實驗》2023-2024學年第二學期期末試卷
- 遼陽職業(yè)技術(shù)學院《外貿(mào)函電與單證》2023-2024學年第二學期期末試卷
- 北京協(xié)和醫(yī)學院《需求分析與系統(tǒng)設(shè)計(雙語)》2023-2024學年第二學期期末試卷
- 四川電力職業(yè)技術(shù)學院《WTO-TBT基礎(chǔ)知識》2023-2024學年第二學期期末試卷
- 2022年云上貴州大數(shù)據(jù)(集團)有限公司招聘筆試試題及答案解析
- 高考報名資格審查表
- (虎符銅砭刮痧)基本理論及臨床應(yīng)用課件
- 文件袋、檔案袋密封條模板
- 依圖科技業(yè)務(wù)概述
- 支氣管鏡室工作制度
- 船模制作教程(課堂PPT)課件(PPT 85頁)
- 防腐檢查培訓教材ppt課件
- 天藍色商務(wù)發(fā)展歷程時間軸PPT模板課件
- 肺炎鏈球菌肺炎醫(yī)學PPT課件
- 小學英語微課ppt
評論
0/150
提交評論