亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

隊(duì)列比較

隊(duì)列

無(wú)鎖隊(duì)列Disruptor原理解析

隊(duì)列比較

總結(jié):

就性能而言,無(wú)鎖(什么也不加) > CAS > LOCK;

從現(xiàn)實(shí)使用中考慮,我們一般選擇有界隊(duì)列(避免生產(chǎn)者速度過(guò)快,導(dǎo)致內(nèi)存溢出);同時(shí),為了減少JAVA的垃圾回收對(duì)系統(tǒng)性能的影響,會(huì)盡量選擇array/heap格式的數(shù)據(jù)結(jié)構(gòu)。所以我們實(shí)際使用中用ArrayBlockingQueue多一些;

注:之后會(huì)將ArrayBlockingQueue和Disruptor做一些對(duì)比。

 

Disruptor是什么

 

Disruptor是英國(guó)外匯交易公司LMAX開(kāi)發(fā)的一個(gè)高性能隊(duì)列,研發(fā)的初衷是解決內(nèi)存隊(duì)列的延遲問(wèn)題(在性能測(cè)試中發(fā)現(xiàn)竟然與I/O操作處于同樣的數(shù)量級(jí))。基于Disruptor開(kāi)發(fā)的系統(tǒng)單線程能支撐每秒600萬(wàn)訂單,2010年在QCon演講后,獲得了業(yè)界關(guān)注。2011年,企業(yè)應(yīng)用軟件專家Martin Fowler專門(mén)撰寫(xiě)長(zhǎng)文介紹。同年它還獲得了Oracle官方的Duke大獎(jiǎng)。

目前,包括Apache Storm、Camel、Log4j 2等在內(nèi)的很多知名項(xiàng)目都應(yīng)用了Disruptor以獲取高性能。

無(wú)鎖隊(duì)列Disruptor原理解析

 


無(wú)鎖隊(duì)列Disruptor原理解析

 

數(shù)據(jù)來(lái)自:

https://github.com/LMAX-Exchange/disruptor/wiki/Performance-Results

Disruptor原理解析

 

CPU緩存

無(wú)鎖隊(duì)列Disruptor原理解析

 

緩存層級(jí)越接近于 CPU core,容量越小,速度越快,當(dāng) CPU 執(zhí)行運(yùn)算的時(shí)候,它先去 L1 查找所需的數(shù)據(jù),再去 L2,然后是 L3,最后如果這些緩存中都沒(méi)有,所需的數(shù)據(jù)就要去主內(nèi)存拿。走得越遠(yuǎn),運(yùn)算耗費(fèi)的時(shí)間就越長(zhǎng)。

 

緩存行

無(wú)鎖隊(duì)列Disruptor原理解析

 

緩存行 (Cache Line) 是 CPU Cache 中的最小單位,CPU Cache 由若干緩存行組成,一個(gè)緩存行的大小通常是 64 字節(jié)(這取決于 CPU),并且它有效地引用主內(nèi)存中的一塊地址。一個(gè) Java 的 long 類型是 8 字節(jié),因此在一個(gè)緩存行中可以存 8 個(gè) long 類型的變量。

CPU每次從主存中拉取數(shù)據(jù)時(shí),會(huì)把相鄰的數(shù)據(jù)也存入同一個(gè)cache line。

在訪問(wèn)一個(gè)long數(shù)組的時(shí)候,如果數(shù)組中的一個(gè)值被加載到緩存中,它會(huì)自動(dòng)加載另外7個(gè)。因此你能非常快的遍歷這個(gè)數(shù)組。事實(shí)上,你可以非常快速的遍歷在連續(xù)內(nèi)存塊中分配的任意數(shù)據(jù)結(jié)構(gòu)。

 

利用CPU緩存-示例

無(wú)鎖隊(duì)列Disruptor原理解析

 

偽共享

無(wú)鎖隊(duì)列Disruptor原理解析

 

如果多個(gè)線程的變量共享了同一個(gè) CacheLine,任意一方的修改操作都會(huì)使得整個(gè) CacheLine 失效(因?yàn)?CacheLine 是 CPU 緩存的最小單位),也就意味著,頻繁的多線程操作,CPU 緩存將會(huì)徹底失效,降級(jí)為 CPU core 和主內(nèi)存的直接交互。

 

如何解決偽共享(字節(jié)填充)

無(wú)鎖隊(duì)列Disruptor原理解析

 


無(wú)鎖隊(duì)列Disruptor原理解析

 

RingBuffer

無(wú)鎖隊(duì)列Disruptor原理解析

 

在Disruptor中采用了數(shù)組的方式保存了我們的數(shù)據(jù),上面我們也介紹了采用數(shù)組保存我們?cè)L問(wèn)時(shí)很好的利用緩存,但是在Disruptor中進(jìn)一步選擇采用了環(huán)形數(shù)組進(jìn)行保存數(shù)據(jù),也就是RingBuffer。在這里先說(shuō)明一下環(huán)形數(shù)組并不是真正的環(huán)形數(shù)組,在RingBuffer中是采用取余的方式進(jìn)行訪問(wèn)的,比如數(shù)組大小為 10,0訪問(wèn)的是數(shù)組下標(biāo)為0這個(gè)位置,其實(shí)10,20等訪問(wèn)的也是數(shù)組的下標(biāo)為0的這個(gè)位置。

當(dāng)然其不僅解決了數(shù)組快速訪問(wèn)的問(wèn)題,也解決了不需要再次分配內(nèi)存的問(wèn)題,減少了垃圾回收,因?yàn)槲覀?,10,20等都是執(zhí)行的同一片內(nèi)存區(qū)域,這樣就不需要再次分配內(nèi)存,頻繁的被JVM垃圾回收器回收。

 

實(shí)際上,在這些框架中取余并不是使用%運(yùn)算,都是使用的&與運(yùn)算,這就要求你設(shè)置的大小一般是2的N次方也就是,10,100,1000等等,這樣減去1的話就是,1,11,111,就能很好的使用index & (size -1),這樣利用位運(yùn)算就增加了訪問(wèn)速度。 如果在Disruptor中你不用2的N次方進(jìn)行大小設(shè)置,他會(huì)拋出buffersize必須為2的N次方異常。

 

Disruptor生產(chǎn)者和消費(fèi)者

 

生產(chǎn)者寫(xiě)入數(shù)據(jù)

 

寫(xiě)入數(shù)據(jù)的步驟包括:

1.占位;

2.移動(dòng)游標(biāo)并填充數(shù)據(jù);

 

需要考慮的問(wèn)題:

1.如何避免生產(chǎn)者的生產(chǎn)速度過(guò)快而造成的新消息覆蓋了未被消費(fèi)的舊消息的問(wèn)題;

2.如何解決多個(gè)生產(chǎn)者搶占生產(chǎn)位的問(wèn)題;

 

無(wú)鎖隊(duì)列Disruptor原理解析

 

1.如何避免生產(chǎn)者的生產(chǎn)速度過(guò)快而造成的新消息覆蓋了未被消費(fèi)的舊消息的問(wèn)題;

答:生產(chǎn)者獲取占位之前需要查看當(dāng)前最慢的消費(fèi)者位置,如果當(dāng)前要發(fā)布的位置比消費(fèi)者大,就等待;

2.如何解決多個(gè)生產(chǎn)者搶占生產(chǎn)位的問(wèn)題;

多個(gè)生產(chǎn)者通過(guò)CAS獲取生產(chǎn)位;

 

消費(fèi)者讀取數(shù)據(jù)

無(wú)鎖隊(duì)列Disruptor原理解析

 

說(shuō)明:

1.一個(gè)消費(fèi)者一個(gè)線程;

2.每個(gè)消費(fèi)者都有一個(gè)游標(biāo)表示已經(jīng)消費(fèi)到哪了(Sequence);

3.消息者會(huì)等待(waitFor)新數(shù)據(jù),直到生產(chǎn)者通知(signal);

需要考慮的問(wèn)題:

如何防止讀取的時(shí)候,讀到還未寫(xiě)的元素?

 

WaitStrategy(等待策略):

BlockingWaitStrategy:默認(rèn)策略,沒(méi)有獲取到任務(wù)的情況下線程會(huì)進(jìn)入等待狀態(tài)。cpu 消耗少,但是延遲高。

TimeoutBlockingWaitStrategy:相對(duì)于BlockingWaitStrategy來(lái)說(shuō),設(shè)置了等待時(shí)間,超過(guò)后拋異常。

BusySpinWaitStrategy:線程一直自旋等待。cpu 占用高,延遲低.

YieldingWaitStrategy:嘗試自旋 100 次,然后調(diào)用 Thread.yield() 讓出 cpu。cpu 占用高,延遲低。

SleepingWaitStrategy:嘗試自旋 100 此,然后調(diào)用 Thread.yield() 100 次,如果經(jīng)過(guò)這兩百次的操作還未獲取到任務(wù),就會(huì)嘗試階段性掛起自身線程。此種方式是對(duì)cpu 占用和延遲的一種平衡,性能不太穩(wěn)定。

 

生產(chǎn)者寫(xiě)入數(shù)據(jù)示例1

無(wú)鎖隊(duì)列Disruptor原理解析

 

生產(chǎn)者寫(xiě)入數(shù)據(jù)示例2

無(wú)鎖隊(duì)列Disruptor原理解析

 

總結(jié)

Disruptor與ArrayBlockingQueue不同的地方:

 

1.增加緩存行補(bǔ)齊, 提升cache緩存命中率, 沒(méi)有為偽共享和非預(yù)期的競(jìng)爭(zhēng);

2. 可選鎖無(wú)關(guān)lock-free, 沒(méi)有競(jìng)爭(zhēng)所以非常快;

3. 環(huán)形數(shù)組中的元素不會(huì)被刪除;

4. 支持多個(gè)消費(fèi)者,每個(gè)消費(fèi)者都可以獲得相同的消息(廣播)。 而ArrayBlockingQueue元素被一個(gè)消費(fèi)者取走后,其它消費(fèi)者就無(wú)法從Queue中取到;

分享到:
標(biāo)簽:隊(duì)列
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定