2012-03-20 190 views
7

我正在寫一個異步日誌記錄框架,我有多個線程轉儲數據。我開始玩Boost asio,因爲它提供了一些簡單的方法來執行序列化和訂購。因爲我是初學者,所以我開始使用線程安全(使用boost::mutexboost:condition_variable)circular bounded_buffer(實際上是vector)的設計。Boost ASIO IO_SERVICE實現?

我寫了一個簡單的基準來測量性能。基準測試只是一個記錄一百萬條消息的單線程(將它推入緩衝區),而我的工作線程只會從隊列中獲取消息以登錄到文件/控制檯/記錄器列表。 (P.S.使用互斥體和C.V是正確的,消息的指針正在移動,所以從這個角度來看,一切都很好/有效)。

當我改變了我的執行,而不是使用boost::asio::io_service和和具有單個線程執行run()性能確實提高了(其實它真的縮放以及對增加在我最初的簡單模型,而不是降低性能正在記錄的信息的數量)

這裏有幾個問題,我想清除。

  1. 爲什麼要提高性能? (我認爲boost::asio::io_service內部實現具有處理程序的線程安全隊列,這使得它比我自己的初始簡單線程安全隊列設計更有效率)。請注意,我的設計經過了充分的審查,沒有出現任何錯誤(骨架代碼基於已證明的示例),是否有人可以更詳細地瞭解io_service如何實現此目的的內部細節。第二個有趣的觀察是,在增加線程時,我的初始實現性能得到了改善,但是以丟失序列化/排序爲代價,但性能隨boost :: asio降低(非常輕微)(我認爲這是因爲我的處理程序做了非常簡單的任務,並且上下文切換開銷正在下降,我會嘗試執行更復雜的任務並在稍後發佈我的觀察結果)。

  2. 我真的很想知道boost::asio只是用於I/O和網絡操作,還是我用它來通過線程池執行並行任務(並行)是一種很好的設計方法。 io_service對象只是用於I/O對象(如文檔中所寫),但我發現它是一種非常有趣的方式,可以幫助我以序列化的方式解決併發任務(不僅僅是I/O或與網絡相關的任務)使用股線進行排序)。我很興奮,並且很好奇爲什麼基本模型沒有執行/縮放以及當我使用boost asio。

結果:(在我剛1個工作線程)

  • 1000任務:在這兩種情況下
  • 10微秒/任務
  • 10000任務:80微秒(有界緩衝液),在升壓10微秒ASIO
  • 100000任務:250微秒(bounde緩衝液),在升壓10微秒ASIO

這將是有趣到k現在如何提升解決線程安全問題io_service處理程序的線程安全隊列(我總是認爲在某種程度上的實現,他們也必須使用鎖和c.v)。

+0

我已經使用'boost :: asio'來管理其他類型的異步任務(不僅僅是網絡IO)以取得良好的成功。 – Chad 2012-03-20 15:13:00

+0

我知道這是一個老問題,但可能(在Windows上),ASIO使用IO完成端口,這可能會導致總體系統調用較少。 – Pete 2013-10-22 08:21:09

回答

4

我怕我忍不住多用(1),但相對於其他兩個問題:

(2)我發現有在boost::asio架構的一些費用是不 - 確定性的,即進入(或發送到IO服務對象)的數據之間的延遲可以從幾乎即時響應變化到幾百毫秒的量級。我試圖量化這個問題,作爲我試圖解決的關於記錄和時間戳RS232數據的另一個問題的一部分,但沒有得到任何確定的結果或穩定延遲的方法。我不會感到驚訝的發現類似的問題存在於上下文切換組件中。 (3)就異步I/O以外的任務而言,使用boost::asio,它現在是我大部分異步操作的標準工具。我一直使用boost::asio定時器進行異步處理,併爲其他任務生成超時。將多個工作線程添加到池中的能力意味着您可以很好地擴展其他異步高負載任務的解決方案。我簡單和最喜歡的課我已經寫在過去的一年是boost::asio IO服務一個小小的工作線程類(道歉,如果有任何錯別字,這是從內存中轉錄,而不是切&粘貼):

class AsioWorker 
{ 
public: 
    AsioWorker(boost::asio::io_service * service): 
    m_ioService(service), m_terminate(false), m_serviceThread(NULL) 
    { 
    m_serviceThread = new boost::thread(boost::bind(&AsioWorker::Run, this)) 
    } 
    void Run(void) 
    { 
    while(!m_terminate) 
     m_ioService->poll_one(); 
     mySleep(5); // My own macro for cross-platform millisecond sleep 
    } 
    ~AsioWorker(void) 
    { 
    m_terminate = true; 
    m_serviceThread->join(); 
    } 
private: 
    bool m_terminate; 
    boost::asio::io_service *m_ioService; 
    boost::thread *m_serviceThread; 
} 

這個班級是一個很棒的小玩具,只需要加上new就可以了,有些則在delete之後。將一個std::vector<AsioWorker*> m_workerPool粘貼到使用boost::asio的設備類中,您甚至可以進一步包裝線程池管理內容。我一直很想寫一個智能池自動管理器,根據時間適當增加線程池,但是我還沒有一個項目需要它。

關於滿足您對線程安全的好奇心,可以深入瞭解提升的內容,以準確找出他們如何完成自己的工作。就我個人而言,我總是將大部分提升的東西用於面值,並從過去的經驗中認爲它在引擎蓋下非常優化。

0

我也發現boost::asio是一般多核處理引擎的優秀基礎設施。我在很多同步的細粒度任務上測量了它的性能,發現它的性能超過了我使用C++ 11線程和條件變量編寫的「經典」實現。

它也跑贏TBB,但不是那麼多。我深入研究他們的代碼,試圖找到「祕密」。我唯一能想到的就是他們的隊列是一個經典的鏈表,而不是一個stl容器。

對於這一切,我不知道如何asio將縮減在大量線程架構像至強融核。這兩個東西,似乎缺少有:

  1. 優先級隊列和
  2. 一個工作竊取隊列。

我懷疑添加這些功能會降低到TBB性能水平。