數據三層緩衝區IoArgs調度優化

一、三層緩衝區

Packet

IoArgs

Frame

 

二、三者的管理者

Packet是AsyncSendDispatcher或者AsyncReceiveDispatcher

Frame是AsyncPacketReader或者AsyncPacketWriter

IoArgs比較模糊,IoArgs中持有了一個ByteBuffer,她是本次應該發送或者應該接收的數據的存儲空間。

三、IoArgs持有的ByteBuffer,它承載了當前與網絡最接近的緩衝區。這裏的數據要麼直接輸出到網絡要麼直接從網絡接收數據,所以它是最接近網絡的緩衝區。但是,在發送的時候,首先要註冊一個發送,然後由發送者調用接口,提供一個IoArgs,此時的IoArgs是由reader提供的。reader提供一個IoArgs到發送者後,發送者要將數據進行發送。至於發送成功或者失敗則通過接口進行回調。對於寫操作也是同樣的流程。

當通過reader將數據填充到IoArgs後,交給Sender發送者,發送者發送一份數據的時候,會出現一定的問題,它有可能沒有完全發送完當前IoArgs中的所有數據,它會進入到一個無限循環。

outputCallback就是一個輸出,outputCallback是由線程池中的某一個線程調度的,會運行到相應的run方法。

它其實是一個runnable,在run方法中調用canProviderOutput()方法,也就是可以進行輸出操作了。此時會進行數據的獲取,拿到IoArgs。

拿到IoArgs之後進行寫的操作,寫道channel通道中去。 args.writeTo(channel).

寫的時候有一個循環,必須把當前數據都寫入進去後,纔可以返回。

會通過IoProvider中的一個selector來告訴客戶端是否可以發送數據,當可以發送的時候,也就是網卡就緒的時候,此時會進入寫的狀態,會把數據輸出到SocketChannel當中,但是SocketChannel輸出部分數據時,網卡把它的資源讓給了另一個SocketChannel, 也就是當前一個SocketChannel寫的操作,返回的長度可能是0。0不代表失敗,只代表當前無法進行數據的輸出操作。此時,正確的操作是,放棄當前的循環,重新註冊selector,說還有數據沒有發送完成,你需要在後面還可以發送數據的時候,重新調度我,讓我繼續發送數據。

如果強制輸出,會導致的問題是,當前的socketchannel不能再發送數據了,真正可以發送的數據是由另外的socketchannel來完成的。但是佔用的當前的線程,而其它可發送的socketchannel得不到線程的調度,也就影響了整個調度的性能。

所以,首先要改造的是SockeetChannelAdapter這邊分,需要把當前的判斷語句改造一下。

首先,拿到當前的返回值,如果爲0表示當前是無法發送數據的。

再次判斷是否還有數據輸出,如果有,再次註冊進行發送。如果沒有數據輸出了,則回調已經發送完成。

當再次註冊的時候,它會重新加入到隊列裏面,重新註冊一個selector。當它再次就緒的時候,會回到canProviderOutput(),此時會再次觸發processor.provideIoArgs(),此時的IoArgs不是之前的IoArgs,它是一份新的IoArgs.

如果需要繼續發送之前的那一份IoArgs,需要在callback中添加一個attach字段進行保存。

outputCallback修改爲

 

writeTo方法由

改爲

 

三、讀取操作

inputcallback修改爲

如果在readFrom中調用startReading()和finishReading()會導致上次接收的數據丟失掉,所以需改在AsyncReceiveDispatcher中調用

在調用新的IoArgs中調用開始寫入數據的操作

在消費數據之前,調用已經完成寫入數據的方法

在SocketChannelAdapter的inputCallback和outputCallback回調中,承載了第三層緩衝區消費或者說讀取操作,當IoArgs中有數據或者說沒有完全填充滿的時候,將會通過callBack進行循環調度,直到它消費完成或者說全部填充完。

那麼,在外部調度的地方,註冊一個異步接收postReceiveAsync()或者註冊一個異步發送PostSendAsync()中進行一下判斷,判斷一下當前附加部分是否爲空,如果爲空,代表爲正確的狀態,如果callback不爲空,表明callback自身還在進行自循環,理論來說,不應該由外部來調用它來進行再次註冊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章