www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > > IOT物聯(lián)網(wǎng)小鎮(zhèn)
[導(dǎo)讀]作?者:道哥,10年嵌入式開發(fā)老兵,專注于:C/C、嵌入式、Linux。關(guān)注下方公眾號,回復(fù)【書籍】,獲取Linux、嵌入式領(lǐng)域經(jīng)典書籍;回復(fù)【PDF】,獲取所有原創(chuàng)文章(PDF格式)。目錄單片機(jī)中常用的環(huán)形緩沖區(qū)多線程異步日志:雙緩沖機(jī)制雙緩沖機(jī)制為什么高效盡可能的降低Lock...



目錄
  • 單片機(jī)中常用的環(huán)形緩沖區(qū)


  • 多線程異步日志:雙緩沖機(jī)制


  • 雙緩沖機(jī)制為什么高效


  • 盡可能的降低 Lock 的時間


  • 參考代碼


  • 可以繼續(xù)優(yōu)化的地方



別人的經(jīng)驗,我們的階梯!


大家好,我是道哥,今天我為大伙兒解說的技術(shù)知識點(diǎn)是:【在多線程環(huán)境下,如何實(shí)現(xiàn)一個高效的日志系統(tǒng)】。


在很久之前,曾經(jīng)寫過一篇文章《【最佳實(shí)踐】生產(chǎn)者和消費(fèi)者模式中的雙緩沖技術(shù)》,討論了:在一個產(chǎn)品級的日志系統(tǒng)中,如何利用雙緩沖機(jī)制來解決生產(chǎn)者-消費(fèi)者相關(guān)的問題。


前段時間,有位小伙伴私信給我,希望可以具體聊一下這個實(shí)現(xiàn)方案。


本來答應(yīng)在國慶期間完成的,但是我的拖延癥一犯再犯,一直拖到今天,終于把這個作業(yè)給補(bǔ)上了。


雙緩沖這個思路并不是我原創(chuàng)的,而是參考了大神陳碩老師的一本書《Linux 多線程服務(wù)端編程》


從書名就可以看出,討論的是服務(wù)器端的相關(guān)編程內(nèi)容,而且是多線程場景下的,因此可以隱約看出,書中給出的參考代碼的質(zhì)量是很高的。


如果您的主力開發(fā)語言是 C ,強(qiáng)烈推薦您去研究下這本書。


很多 C 語言的細(xì)節(jié)問題,作者都給出了自己專業(yè)、嚴(yán)謹(jǐn)?shù)乃伎己徒鉀Q方案。


言歸正傳!


在上一篇文章中,我主要從思路、概念的角度,來描述如何利用雙緩沖機(jī)制。


這篇文章,我們就忠于書中原文,一起來學(xué)習(xí)一下作者的思考過程,并給出一些對性能起決定作用的關(guān)鍵代碼。


先來看一下書中的性能測試結(jié)果:


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!

單片機(jī)中常用的環(huán)形緩沖區(qū)

一說到緩沖區(qū),相信各位小伙伴一定看過很多關(guān)于緩沖緩沖區(qū)的文章和代碼,在單片機(jī)中的使用率很高。


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!所謂的環(huán)形緩沖區(qū),就是一塊平整的內(nèi)存區(qū)域,讓它的尾部連接到首部即可。


另一個類似的結(jié)構(gòu):環(huán)形隊列,本質(zhì)上都是一樣的。


維護(hù)環(huán)形緩沖區(qū)的數(shù)據(jù)結(jié)構(gòu)中,有head和tail指針。


當(dāng)寫入的時候,把輸入寫入到tail指針的位置,寫完之后,遞增tail的指針值;


當(dāng)讀取的時候,從head指針的位置開始讀取,讀完之后,也遞增head的指針值。


這樣的操作方式,比較適合那種簡單的單輸入、單輸出場景。


只要處理好:當(dāng) head 和 tail 這兩個指針交匯的時候如何處理即可。


但是在x86的操作系統(tǒng)中,在多核 多線程的工作環(huán)境下,無論是從功能上、還是從性能上來考慮,這樣的環(huán)形緩沖區(qū)就滿足不了需求了。


還是拿日志系統(tǒng)來舉例:在一個應(yīng)用程序中,可能會有多個線程同時調(diào)用日志系統(tǒng)的寫入API接口函數(shù),這就需要保證線程安全。


這樣的線程稱作 前臺/前端 線程。


日志數(shù)據(jù)存儲在內(nèi)存中之后,最終是要輸出的,比如:寫入到文件系統(tǒng)、通過網(wǎng)絡(luò)上傳到服務(wù)端、輸出到其他的監(jiān)控系統(tǒng)等等。


實(shí)現(xiàn)輸出操作的也是一個線程,假如需要寫入到文件系統(tǒng),那么在寫入期間,這個線程就需要一直持有緩沖區(qū)中的日志數(shù)據(jù)。


這樣的線程稱作 后臺/后端 線程。


但是,文件系統(tǒng)的寫入速度是很慢的(畢竟要操作硬盤啊),如果這個時候又有前臺線程需要寫日志信息了,該如何處理?


總不能暴力的說:后臺線程正在把現(xiàn)有的日志數(shù)據(jù)存儲到硬盤上,已經(jīng)持有了內(nèi)存緩沖區(qū),前臺線程你是后來的,先等著!


多線程異步日志:雙緩沖機(jī)制

在這本書中,作者對這樣的日志系統(tǒng)規(guī)定了幾個關(guān)鍵的要求,都是與實(shí)際的業(yè)務(wù)需求相關(guān)的:


  1. 線程安全:多個線程可以并發(fā)寫日志,不造成競爭,兩個線程的日志信息不會交叉出現(xiàn);


  2. 吞吐量大;


  3. 日志消息有多種級別,格式可配置等等;


為了達(dá)到這個目的,作者提出了“雙緩沖”思路(Double Buffering)


基本思路是:


準(zhǔn)備兩塊 buffer: A 和 B;


前端負(fù)責(zé)往 buffer A 填數(shù)據(jù)(日志信息);


后端負(fù)責(zé)把 buffer B 的數(shù)據(jù)寫入文件。


當(dāng) buffer A 寫滿之后,交換 A 和 B,讓后端將 buffer A 的數(shù)據(jù)寫入文件,而前端則往 buffer B 填入新的日志信息,如此反復(fù)。


其實(shí)還是蠻好理解的哈,我們還是來畫圖描述一下:


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!當(dāng) buffer A 寫滿之后,交換兩個緩沖區(qū):


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!

雙緩沖機(jī)制為什么高效

使用兩個buffer緩沖區(qū)的好處是:


大部分的時間中,前臺線程和后臺線程不會操作同一個緩沖區(qū),這也就意味著前臺線程的操作,不需要等待后臺線程緩慢的寫文件操作(因為不需要鎖定臨界區(qū))。


還有一點(diǎn)就是:后臺線程把緩沖區(qū)中的日志信息,寫入到文件系統(tǒng)中的頻率,完全由自己的寫入策略來決定,避免了每條新日志信息都觸發(fā)(喚醒)后端日志線程。


例如:可以根據(jù)實(shí)際使用場景,定義一個刷新頻率,例如:3秒。


只要刷新時間到了,即使緩沖區(qū)中的日志信息很少,也要把它們存儲到文件系統(tǒng)中。


換言之,前端線程不是將一條條日志信息分別傳送給后端線程,而是將多條信息拼成一個大的 buffer 傳送給后端,相當(dāng)于是批量處理,減少了線程喚醒的頻率,降低開銷。


盡可能的降低 Lock 的時間

在剛才的描述中,有這么一句話:在[大部分的時間中],前臺線程和后臺線程不會操作同一個緩沖區(qū)。


也就是是說,在小部分時間內(nèi),它們還是有可能操作同一個緩沖區(qū)的。


那就是:當(dāng)前臺的寫入緩沖區(qū) buffer A 被寫滿了,需要與 buffer B 進(jìn)行交換的時候


交換的操作,是由后臺線程來執(zhí)行的,具體流程是:


  1. 后臺線程被喚醒,此時 buffer B 緩沖區(qū)是空的,因為在上一次進(jìn)入睡眠之前,buffer B 中數(shù)據(jù)已經(jīng)被寫入到文件系統(tǒng)中了;


  2. 把 buffer A 與 buffer B 進(jìn)行交換;


  3. 把 buffer B 中的數(shù)據(jù)寫入到文件系統(tǒng);


  4. 開始休眠;


在第2個步驟中:交換緩沖區(qū),就是把兩個指針變量的值交換一下而已,利用C語言中的swap操作,效率很高。


在執(zhí)行交換緩沖區(qū)的時候,可能會有前臺線程寫入日志,因此這個步驟需要在 Lock 的狀態(tài)下執(zhí)行。


可以看出:這個雙緩沖機(jī)制的前后臺日志系統(tǒng),需要鎖定的代碼僅僅是交換兩個緩沖區(qū)這個動作,Lock 的時間是極其短暫的!這就是它提高吞吐量的關(guān)鍵所在!


參考代碼

在示例代碼中,作者對雙緩沖機(jī)制進(jìn)行了擴(kuò)展,采用4個緩沖區(qū),這樣可以進(jìn)一步減少或避免前端線程的等待時間。


數(shù)據(jù)結(jié)構(gòu)如下:


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!這里的nextBuffer_相當(dāng)有是currentBuffer_的“備胎”。


當(dāng)前臺線程發(fā)現(xiàn)currentBuffer_不可用時(空間已滿,或者正在被后臺線程操作),可以立刻寫入到這個"備胎"緩沖區(qū)中,從而降低了前臺線程的等待時間。


下面是前臺線程的寫入代碼:


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!前端線程在生成一條日志消息的時候,會調(diào)用append()函數(shù)。


在這個函數(shù)中,如果當(dāng)前緩沖區(qū)(currentBuffer_)剩余的空間足夠大,直接把消息消息拷貝(追加)進(jìn)去,這是最常見的情況。


如果當(dāng)前緩沖區(qū)的剩余空間,小于這次日志信息的寫入長度,就把它移動到 buffer_ 集合中(一個Vector),此時會發(fā)送喚醒信號給后端線程,然后把nextBuffer_這個備胎 move 為currentBuffer_。


move 是 C 中的操作,意思是移動,而不是拷貝/復(fù)制。


當(dāng)然了,如果前端的寫入速度太快,一下子就把兩塊緩沖區(qū)都用完了,那么只好分配一塊新的 buffer 作為當(dāng)前緩沖區(qū),這是極少發(fā)生的情況。


再來看看后端的代碼實(shí)現(xiàn),這里只貼出了最關(guān)鍵的臨界區(qū)內(nèi)的代碼,也就是前文所說的“小部分時間”的情況:


多線程異步【日志系統(tǒng)】,高效、強(qiáng)悍的實(shí)現(xiàn)方式:雙緩沖!這段代碼中最重要的就是 swap 函數(shù),它把前后臺使用的緩沖區(qū)進(jìn)行了交換


當(dāng)前后臺緩沖區(qū)交換之后,就離開了臨界區(qū),此時后臺線程就可以慢慢的往文件系統(tǒng)中寫入數(shù)據(jù)了。


另外,這段代碼中還有一個地方比較有意思,就是對備胎nextBuffer_的操作:


當(dāng)前臺中使用的備胎nextBuffer_已經(jīng)被消耗掉時,后臺線程及時地為它補(bǔ)充一個新的備胎。


可以繼續(xù)優(yōu)化的地方

在本章的最后部分,作者提出了一個更加嚴(yán)苛的情況:


異步日志系統(tǒng)中,使用了一個全局鎖,盡管臨界區(qū)很小,但是如果線程數(shù)目較多,鎖爭用也可能影響性能。


一種解決方法是像 Java 的 ConCurrentHashMap 那樣使用多個桶子(bucket),前端線程寫日志的時候根據(jù)線程id哈希到不同的 bucket 中,以減少競爭。


這種解決方案本質(zhì)上就是提供更多的緩沖區(qū),并且把不同的緩沖區(qū)分配給不同的線程(根據(jù)線程 id 的哈希值)。


那些哈希到相同緩沖區(qū)的線程,同樣是存在爭用的情況的,只不過爭用的概率被降低了很多



------ End ------
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉
關(guān)閉