標籤:java nio 非同步 最佳化
dawn的協程庫,使用的是kilim,不過已經遠非kilim的原有代碼,主要保留了協程的兩個基本原語,再往上層,已經全部被替換了。
協程庫,我學習過boost asio中的協程,也在我的機器上測試過單純環境切換的速度。這個速度在不同的機器之間沒有可比性,因為彼此的cpu可能不同。但是在同一台機器上的不同庫的對比,具有一定的參照性。
我記得,當時asio協程單線程情況下,協程切換的最高持續輸送量大概是400萬次每秒。
我當時是準備使用kilim,所以在同一時間也測試了kilim,我記得當時測試出來的持續輸送量大約是260萬次左右,當時稍微有點失望,不過拿asio參考的話,也達到了50%以上,所以,也就採用了kilim。
在前一段時間寫dawn的時候,我專門最佳化過協程這塊,最開始用的是紅/黑樹狀結構做的定時器,跑的最大持續輸送量大概是360-380萬每秒。我懷疑是紅/黑樹狀結構在不穩定的情況下發生了過多的翻轉,導致了額外的開銷。
於是,第二天,寫了一個時間輪,換上去之後,不停的調整參數,測試輸送量,發現還是380萬左右。無論怎麼調,都上不去。用jprofiler檢測,看不出來明顯的毛病,當時給我的感覺就是慢在記憶體的訪問上,因為我的時間輪的每個tick用的都是鏈表。我下意思裡覺得是慢在這,不過這已經是最簡單的鏈表了,還能怎麼最佳化?
就這樣,我暫停了最佳化,全部精力投入了工作以及dawn的完善以及bug修改。
兩周后的今天,早上醒來後,我躺在床上,就瞎琢磨了一下,就想到了這個問題,突然想,如果把tick上的鏈表換成迴圈隊列呢?試試,立馬起床,寫了一個迴圈隊列,為了避免迴圈隊列溢出,我在迴圈隊列的內部加上了鏈表,把超出迴圈隊列容量的元素放入鏈表。我把迴圈隊列的大小開到了10萬。用迴圈隊列代替了鏈表,開啟測試案例,這次居然能跑到560萬次每秒了,說明思路對了。我就調了調參數,大概把迴圈隊列的大小設定為5萬的時候,平衡性最好,輸送量大約是600萬每秒。看看時間,也寫了將近一個小時了,於是我又躺著看了會新聞。
覺得這個迴圈隊列+鏈表的方式還不夠好,因為迴圈隊列滿的時候會啟用鏈表,加大了開銷,反而會在繁忙的時候降低輸送量。如果只用迴圈隊列而不用鏈表,又怕會溢出。突然,我想到,如果把鏈表的每個節點擴大點擴充成數組,不就結了。
立馬動手,寫了一個LinkedArrayList,數組鏈表,這樣就不怕溢出了,也會保持很高的效能。換掉剛才的迴圈隊列,運行測試案例,不出意外,第一次就跑到了600多萬,經過10多分鐘的參數調整,最後,把數組長度定為5000,單個線程,20萬協程,協程環境切換達到700多萬次每秒。
達到這個速度,還是很超出我的預期的,我最開始覺得能到500多萬就滿足了,最終到了700多萬。
於是我又測試了一下定時任務,竟然執行了到了1100萬次每秒,以往最好的記錄大約是900多萬,這足以說明,這次改進降低了協程調度的成本。
其實調度速度的快慢並沒有決定意義,但是,這可以給上層應用一個更好的基礎,讓出更多的cpu資源給應用程式,或者是讓應用可以使用更多的協程,讓系統繁忙的時候啟動並執行更有效率。
好吧,先調到這裡吧,到這裡,已經暫時達到我現有水平的極限了。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
[NIO]從300萬到700萬——dawn的協程最佳化