LF模式是個坑,ZeroIce中介軟體讓你體會這個痛

2022-07-06 20:24:16 字數 2908 閱讀 9466

lf模式是個坑,乙個小小的失誤就可能使你的網路處理癱瘓,ice就很好地展現了出來,換句話說,ice中介軟體或是lf模式就是乙個坑,如果你一不小心。

lf模式的官方**中,論述了此模式用於高效能網路併發模式,使用的是系統的隱式佇列,也就是reactor復用多路io,(如果是select的話,還是會將事件收集到乙個顯式佇列),每次只有一條執行緒可以有一次機會成為leader訪問這個佇列,從佇列取出事件後放棄leader,同時喚醒另一線程(如果還有follower執行緒的話);注意這時的執行緒既不是leader也不是follower,它就可以處理事件,一般就是同步非阻塞讀寫,然後處理這個請求(通常來說就是dispatchfromthisthread)。當上面的工作結束就,才會作為follower等待成為leader,如果沒有leader的話就會馬上成為leader。在這種模式中,稱為lf模式有點誤導,因為實際上是三種狀態,lpf,leader,process,follower,狀態機為 l->p->f->l->...。follower狀態的執行緒阻塞等待著leader離開leader狀態去process,從而喚醒可能的follower狀態的執行緒。被喚醒的follower執行緒狀態變為leader,成為執行緒池中唯一當前有權操作佇列的執行緒,要麼阻塞在空佇列,要麼取出佇列乙個事件離開leader狀態去process。執行緒池執行緒當process完事件後才會狀態變為follower,或者阻塞等待leader的喚醒,或者自動成為leader。狀態機就為 l(block on event queue)->p->f->(block on followers queue)->l ...。在這種模式下的執行緒池中,最多只有乙個執行緒在leader狀態,並且只有這個leader執行緒可以阻塞在io事件佇列,其它執行緒要麼在process狀態處理事件,要麼就是在follower狀態等待成為下乙個leader。當沒有io事件的時候,就只有乙個執行緒在leader狀態阻塞在io事件佇列,其它執行緒都結事了事件的處理,並在follower狀態阻塞等待leader執行緒釋放訊號。

通常用來襯托lf模式的,就是sync/async模式,並且都會舉例manager-workers執行緒池。manager負責將佇列的事件指派到空閒worker執行緒進行處理。worker執行緒被喚醒處理完事件後再次阻塞等待manager喚醒。當沒有事件的時候,manager阻塞在事件佇列,worker執行緒阻塞等待manager執行緒喚醒。這種執行緒池有乙個固定執行緒去阻塞在事件佇列。並且每次manager喚醒worker都要通過堆來傳遞事件。(manager從事件佇列取出乙個事件寫入到堆記憶體,worker從堆記憶體讀到自己的棧,然後處理棧上的這個事件;而leader從事件佇列將乙個事件讀到自己的棧,再就喚醒其它follower,然後處理棧上的這個事件。)當manager執行緒不負責reactor復用多路io的情況,在空閒時發生了一次io事件必須跨執行緒寫入manager執行緒的事件佇列,並喚醒manager執行緒,然後manager執行緒喚醒worker執行緒去處理事件。而lf模式執行緒池,leader從系統的多路io復用分離函式中返回,喚醒乙個follower,然後自己去處理事件。這樣一比較就是manager-workers執行緒池進行了兩次執行緒喚醒,而lf模式執行緒池只有乙個執行緒喚醒(這裡必須要公正,leader是之前就被喚醒經歷消耗了一次切換),事件在manager-workers執行緒池需要多次拷貝。

那麼為什麼lf模式不心就會踩坑,而ice的設計就讓體會這個坑。

問題在於如果lf模式執行緒池的執行緒進行process阻塞等待io響應,而所有的執行緒都在process過程中阻塞等待io響應,更重要這些被等待的io應用在這個執行緒池的reactor,就會再也沒有執行緒成為leader去多路io分離函式中讀取io事件。這時候這個lf執行緒池就會癱瘓不工作。ice中介軟體會讓你深深體會這種痛。ice採用activeobject模式進行obr物件**請求。控制線程呼叫proxy請求返回乙個future,阻塞等待future。communicator的clientthreadpool負責reactor,收到請求的response後就向future發訊號,從而喚醒這個response對應的future阻塞住的控制線程。這種情況下使用orb物件**請求的執行緒與網路reactor執行緒池獨立,負責reactor的lf執行緒池不會被其它邏輯影響。但是在lf執行緒池中進行orb物件**請求呢?問題就來了。你的lf執行緒池隨時都可能癱瘓掉,只要你不小心。極端地,lf執行緒池只有乙個執行緒,這個執行緒在process事件時,進行了orb物件**請求,阻塞等待future。good job!! 這個執行緒池中唯一的執行緒就永遠不會再有機會成為leader去取出遠端的response的io事件,去喚醒這個阻塞住執行緒的future了。這還不容易解決,都說是執行緒池,那會只有乙個執行緒的呢。我們讓這個lf執行緒池新增到兩個執行緒,第乙個執行緒取出事件喚醒第二個執行緒,然後自己處理事件時,進行了orb物件**請求,阻塞等待future;第二個執行緒成為leader阻塞在多路io分離函式,並在遠端response到來時,從分離函式返回,得以喚醒了阻塞第乙個執行緒的future。但是很不幸,第二個執行緒在等待到response到來之前,收到其它io事件,而處理這個事件卻進行了orb物件**請求,阻塞等待future。汗,lf執行緒池都被阻塞在future,future又等待io事件。再往下演繹,不論lf執行緒池有多少執行緒,只要你的處理邏輯中進行了同步阻塞的orb物件**請求,都會使你的ice網路處理癱瘓,癱瘓的原因是lf執行緒池癱瘓了。ice的server端線程池預設就在當前執行緒進行請求的dispatch,如果你在實現你的服務的時候必須依賴其它orb物件**請求時,你就要小心了,你可能因為這樣而阻塞掉所有communicator的server端lf執行緒池,至使網路reactor癱瘓。如果你使用了bidirection connection來提供callback的飼服,要是你在callback的實現中依賴了其它orb物件**請求時,你同樣也要小心了,你可能因為這樣而阻塞掉所有communicator的client端lf執行緒池,至使網路reactor癱瘓。ice為了避免,會預設為每個連線加上乙個計時器,讓連線自動斷開。但是我們還是有應用場合希望連線長九不斷開,關閉這種機制,這時就要小心了。再者就是,即使你所有的orb物件請求**都用非同步方式(ami,amd)進行程式設計,但是悲劇的是你無法干涉到你依賴的其它人函式沒有進行同步阻塞的orb物件**請求。

數論是個坑8 鴿巢原理

鴿巢原理 又稱為抽屜原理。其最簡單的形式如下。如果 n 1 個物體被放進 n 個盒子,那麼至少有乙個盒子包含兩個或者兩個以上的物體。證明 如果這 n個盒子中每個都至多含有乙個物體,那麼物體的總數最多是 n,和已知的有 n 1 n 1 個物體矛盾,故某個盒子必然包含兩個及以上的物體。鴿巢原理最簡單的應...

微信是個坑貨1 接入

邏輯 using system using system.collections.generic using system.linq using system.web using system.web.sessionstate using system.web.security using wxpl...

單例模式中的那些坑

單例模式相信大家都有遇到,面試中出現概率還是比較高的,從最基礎的加synchronized鎖到雙重檢查鎖,再到加上volatile關鍵字,小小的乙個單例模式裡還是存在不少問題的,下面先看 基礎的 雙重檢查的 這一步的改善比較好理解,在多執行緒的情況下第乙個方法的效率會低於第二個方法的,第乙個方法會導...