這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)大數(shù)據(jù)中如何淺析多線程數(shù)據(jù)訪問一致性問題及解決方法,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
為托里等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及托里網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、成都做網(wǎng)站、托里網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
服務(wù)器和筆記本電腦都使用多核CPU,出于性能考慮,每個CPU采用了獨(dú)享的Cache機(jī)制(通常有兩級獨(dú)享cache和一級共享cache),由此帶來并發(fā)訪問內(nèi)存中的同一數(shù)據(jù),在不同CPU上的可見性或一致性問題。CPU采用Cache機(jī)制帶來多線程訪問共享數(shù)據(jù)的一致性或數(shù)據(jù)可見性問題,是從事多線程編程的工程師們繞不過去的坎兒。
知道了問題所在,解決并發(fā)訪問下數(shù)據(jù)一致性問題的方法有多種。最常用的就是加鎖方式,比如C/C++下直接使用線程鎖實現(xiàn)訪問互斥,同時也能保證數(shù)據(jù)修改后的可見性。對于計數(shù)器場景,還可以采用性能更高的原子操作(其性能大約是線程鎖的6倍),例如gcc內(nèi)置的 __sync_add_and_fetch / __sync_fetch_and_add 或 __sync_sub_and_fetch / __sync_fetch_and_sub 等函數(shù)。另外可以利用CAS(Compare And Swap)原子操作實現(xiàn)無鎖編程,例如gcc內(nèi)置的__sync_bool_compare_and_swap 和 __sync_val_compare_and_swap。比如我們可以利用CAS實現(xiàn)無鎖隊列。
對于一個生產(chǎn)者和一個消費(fèi)者的線程模型,使用ring buffer這樣的數(shù)據(jù)結(jié)構(gòu),因不存在訪問沖突的問題,可以采用無鎖化編程。比如Linux內(nèi)核處理ring buffer,結(jié)合使用內(nèi)存屏障,可以在無鎖的情況下保證數(shù)據(jù)可見性。內(nèi)存屏障這塊比較深奧,我在這方面沒有研究和實踐,在這里拋個磚就好。
針對一個線程修改數(shù)據(jù),多個線程讀取的場景,一種更為極端的無鎖編程方式:不但徹底無鎖(不需要CAS),而且還不使用內(nèi)存屏障來保證數(shù)據(jù)可見性。這種做法顯然違背了并發(fā)訪問的數(shù)據(jù)一致性,但對于可接受數(shù)據(jù)最終一致的場景,這種做法是完全可行的。這是為什么呢?一個線程修改數(shù)據(jù)后,因CPU cache機(jī)制,其他線程將延遲感知到修改后的數(shù)據(jù)。根據(jù)筆者經(jīng)驗,這個延遲通常在1ms以內(nèi)。因為沒有采用加鎖或內(nèi)存屏障等機(jī)制,數(shù)據(jù)在多線程下的可見性存在不確定性。對于大多數(shù)數(shù)據(jù)結(jié)構(gòu)(如平衡二叉樹、紅黑樹、skiplist、hashtable等)的數(shù)據(jù)修改通常會分為多個步驟完成,在此友情提醒大家,采用這種做法的一個前提條件是,當(dāng)讀取線程讀到部分更新后的數(shù)據(jù)時,不會導(dǎo)致程序邏輯錯亂甚至出現(xiàn)崩潰等異常情況發(fā)生。平衡二叉樹這樣的數(shù)據(jù)結(jié)構(gòu)很難采用這種編程模型(因保持平衡涉及旋轉(zhuǎn)操作,需要一把大鎖保護(hù)),而精心實現(xiàn)的skiplist和hashtable是可以做到的。
上述就是小編為大家分享的大數(shù)據(jù)中如何淺析多線程數(shù)據(jù)訪問一致性問題及解決方法了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。