日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

为什么你不应该接受有 race 的代码

發(fā)布時間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么你不应该接受有 race 的代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在任何語言的并發(fā)編程場景中,都有 race 問題,現(xiàn)代語言為了解決 race 問題有兩種思路,一種是像 rust 那樣的通過所有權(quán)+Sync/Send 限制用戶盡量無法寫出帶 race 的代碼;一種是像 Go 這樣,通過 race detector 在測試期間檢查數(shù)據(jù)競爭問題。

Go 的 race detector 設(shè)計決定了其無法在線上環(huán)境開啟,而很多公司的項目上線前其實是沒有 race test 的環(huán)節(jié)的,這就導(dǎo)致了一些 Gopher 認為我寫出 race 的代碼也沒關(guān)系,因為可以“最終一致”。

在 Go 官方的?《The Go Memory Model》[1]?一文中已經(jīng)駁斥過這些觀點了,比如有這么一個例子:

var?a?string var?done?boolfunc?setup()?{a?=?"hello,?world"done?=?true }func?main()?{go?setup()for?!done?{}print(a) }

全局變量 a 的寫入和 done 的修改從代碼層面講存在先后關(guān)系,但因為你沒有在代碼中使用任何同步工具(哪怕是 atomic 操作),所以這樣的代碼你沒法保證在 for 循環(huán)檢查到 done 變成 true 之后,一定能打印出 "hello, world"。

這里還只是因為 CPU 和編譯器的亂序執(zhí)行導(dǎo)致了問題,按照這些程序員的想法,我不關(guān)心順序,我只關(guān)注最終一致,反正 done 肯定能被改成 true,a 也一定能被修改成 hello, world。

這種想法也是有問題的,多核環(huán)境下 CPU 有多級緩存,如果連 atomic 都不使用,那么在多個核心間也不一定會同步你這種寫行為。最差的情況下,在一個核心里寫了 done = true,另一個核心一直讀不到,這也是正常的(并不好復(fù)現(xiàn))。說不定什么時候硬件為了優(yōu)化就真的會給你這么干啊。

官方給出的這個例子,我們在 build/run 的時候加上簡單的 -race flag,也是可以及時發(fā)現(xiàn)問題的:

~/test?git:master?????go?run?-race?./r.go ================== WARNING:?DATA?RACE Write?at?0x0000011506a1?by?goroutine?6:main.setup()/Users/xargin/test/r.go:8?+0x73Previous?read?at?0x0000011506a1?by?main?goroutine:main.main()/Users/xargin/test/r.go:13?+0x3eGoroutine?6?(running)?created?at:main.main()/Users/xargin/test/r.go:12?+0x32 ================== ================== WARNING:?DATA?RACE Read?at?0x000001121bf0?by?main?goroutine:main.main()/Users/xargin/test/r.go:15?+0x53Previous?write?at?0x000001121bf0?by?goroutine?6:main.setup()/Users/xargin/test/r.go:7?+0x30Goroutine?6?(finished)?created?at:main.main()/Users/xargin/test/r.go:12?+0x32 ================== hello,?worldFound?2?data?race(s) exit?status?66

發(fā)現(xiàn)了有 data race 就一定要去解決,如果允許這樣的代碼進入到你的工程里,那么這樣的錯誤就會越來越多,當(dāng)未來某個時刻你需要去查并發(fā)導(dǎo)致的 bug 了,那成百上千的 race 輸出都是技術(shù)債,到時候再來還就晚了。

如果可以的話,race test 也最好集成在你的 CI 環(huán)境中,初級工程師最擅長的就是這個:

如果你允許有 race 的代碼進入主分支,日積月累會有更多的 race 通過拷貝擴散。

當(dāng)你花了一個星期還沒有辦法定位出線上偶發(fā)的并發(fā)問題的時候,可能就只能提桶跑路了。

要寫并發(fā)相關(guān)的代碼,還是要好好學(xué)習(xí)一下并發(fā)知識的。這里可以推薦兩本相關(guān)的書:《Shared Memory Synchronization》 和 《perfbook》。

[1]

《The Go Memory Model》:?https://go.dev/ref/mem

總結(jié)

以上是生活随笔為你收集整理的为什么你不应该接受有 race 的代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。