計算&IO密集型任務的 優化


問題原因:

最近由於工作實際需求,需要對某個計算單元的計算方法進行重構。原因是由於這個計算單元的計算耗時較長,單個計算耗時大約在1s-2s之間,而新的需求下,要求在20s內對大約1500個計算單元計算完畢。如果不對原有計算單元的計算方法進行優化及效率提升,那么以8核CPU(超線程16線程)來說,在單個計算1s的理想條件,服務器16線程完成任務的理論上限也需要90s+,何況多線程還並不是簡單的效率疊加,實際測試情況下,耗時往往在150s以上。因此,對原有計算單元的計算優化是必須的。

 

問題分析:

通過對原有計算單元的實現過程查看,計算任務存在大量的數據庫讀取及大量的比對、計算等操作,涉及的數據表的數量級從數百到百萬不等,這些數據表有一個相同的特點就是相對固定,並不是實時業務數據。通過對原有計算過程的分析,主要的耗時就在各種條件比對及比對后進行的數據庫IO操作。

因此,要提高效率,首先想到的就是如何減少數據庫的IO次數,但實際的計算任務是一個很嚴格的時序型邏輯,即每一步的處理輸入是上一步的數據處理結果。因此要在單個計算任務中進行並行計算的改造很難,並且,由於單次數據庫IO的時間開銷也不大,因此進行異步化改造也不合適,反而會增加代碼的復雜度。

所以最終還是把思路集中在如何對計算任務本身進行優化。

 

解決方式:

經過對計算任務的分析,在這種場景上下文中,決定以哈希定位作為解決方式(這是一種可能的解決方式,但並不一定是最優的)。

通過前文對計算任務的分析,所涉及的數據都是相對固定的,因此首先考慮將所有數據加載到內存(由於數據量並不是非常的大,服務器內存還能承受,可根據實際需求加載到mem或redis中)。如果僅僅是將數據加載到內存,再用linq2object替代原有的數據庫IO,提升並不大,因為計算邏輯中最耗時的操作是對數據的范圍查詢,即數據並沒有精確匹配,而是需要找到目標值對應數據的上下限,並進行線性插值運算。

如果能將范圍數據查詢的工作以更快速更精確的方式來實現,就省下了計算邏輯中最大的時間開銷。因此考慮才用呢哈希定位的方式進行。

具體改造過程不再贅述,工作難點主要在於哈希KEY的構造,以及如何通過哈希尋址實現數據庫查詢中的‘> and <’條件操作。具體來說,通過將范圍值擴大量綱變為整數,並以最小步長提前做線性插值,即可形成滿足要求的哈希KEY,同時,通過對需要定位的值,對步長進行除法取整,即可得到目標值的下限值,再對下限值加上步長,即可得到上限值,從而通過一次哈希尋址,得到之前需要在數據庫進行‘> and <’操作的結果。

 

解決結果:

通過以上改造,在該計算任務場景中,對1000+計算單元進行計算的時間開銷已降低到1-4秒(由於是WCF服務調用,因此需要視網絡通信等狀況而定),完全可以滿足需求。

 

 

通過對這次計算任務的重構,可以看出,對計算密集型/IO密集型任務,異步化及並行計算等優化方法很難進行,並且提高會非常有限(計算密集型任務),因此,通過對原子任務本身的優化來達到最終目標也是一個重要的思路。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM