2013-03-02 13 views
1

我正在處理一個問題,我想以指定的速率重播存儲在文件中的數據。以固定速率重播存儲的數據

例如:25,000記錄/秒。

該文件採用ascii格式。目前,我讀取文件的每一行,並應用一個正則表達式來提取 的數據。 2到4條線組成一條記錄。我對這個操作進行了計時,並且它在接近 的15微秒內生成每條記錄。

發佈每條記錄所用的時間爲6微秒。

如果我按順序執行讀寫操作,那麼我將以21微秒結束每個記錄的發佈。如此有效,這意味着我的上限是每秒約47K條記錄。

如果我決定多線程讀取和寫入,那麼我將能夠每9微秒發送一個數據包(忽略鎖定懲罰,因爲讀寫器共享相同的Q),從而產生每秒110K刻度的吞吐量。

我以前的設計是否正確?

當單個生產者和消費者共享一個隊列時,什麼樣的隊列和鎖定構造具有最小懲罰?

如果我想超越這個範圍,最好的方法是什麼?

我的應用程序是用C++

回答

1

如果需要15US讀/準備記錄那麼你的最大吞吐量將約1秒/ 15uSec = 67K /秒。您可以忽略6uSec部分,因爲讀取文件的單個線程無法生成更多的記錄。 (嘗試它,改變程序只讀/處理和放棄輸出)不知道如何得到9uS。

爲了使這個飛過了67K /秒......

A)估計每秒可以從磁盤讀取要格式化的最高記錄。雖然這取決於硬件,但平均每檯筆記本電腦的典型值爲20Mb/s。這個數字會給你的目標上限,當你接近你可以放鬆嘗試。 B)創建一個單線程來讀取文件併產生IO延遲。這個線程應該寫入大的預分配緩衝區,比如每個4Mb。有關管理這些的方法,請參見http://en.wikipedia.org/wiki/Circular_buffer。 (!猜測,但不只是8 ISH記錄)您正在尋找持有也許1000個記錄每個緩衝區僞代碼:

while not EOF 
    Allocate big buffer 
    While not EOF and not buffer full 
      Read file using fgets() or whatever 
      Apply only very small preprocessing, ideally none 
      Save into buffer 
    Release buffer for other threads 

C)創建另一個線程(或幾個,如果記錄的順序並不重要)來處理一個環形緩衝區,當它滿了,你的正則表達式的一步。該線程反過來寫入到另一組輸出環緩衝器(尖端,在存儲器保持環形緩衝器控制結構分開)

While run-program 
     Wait/get an input buffer to process, semaphores/mutex/whatever you prefer 
     Allocate output buffer 
     Process records from input buffer, 
      Place result in output buffer 
     Release output buffer for next thread 
     Release input buffer for reading thread 

d)創建你最終螺紋消耗數據。目前還不清楚這個輸出是寫入磁盤還是網絡,所以這可能會影響磁盤讀取線程。

Wait/get input buffer from processed records pool 
    Output records to wherever 
    Return buffer to processed records pool 

注意事項: 預分配所有緩衝區並將它們傳回到它們來自的位置。例如,在文件讀取線程和處理線程之間可能有4個緩衝區,當所有4個緩衝區都注入時,文件讀取器等待一個空閒,它不僅分配新緩衝區。 儘量不memset()緩衝區,如果你可以避免它,浪費內存帶寬。 你不需要很多緩衝區,6?每個環形緩衝區?

系統會自動調整到最慢的線程(http://en.wikipedia.org/wiki/Theory_of_constraints),所以如果您可以讀取和準備數據的速度超過您想要輸出的速度,那麼所有緩衝區都將被填滿,除輸出外,所有緩衝區都將暫停。

由於線程正在傳遞每個同步點的合理數據量,所以這個開銷並不重要。

上面的設計是我的一些代碼如何儘可能快地讀取CSV文件,基本上都是爲了輸入IO帶寬作爲限制因素。

+0

太棒了!這很棒。你的代碼是否是開源的?如果是這樣,你能指出我嗎? – KodeWarrior 2013-03-04 20:15:16

+0

關於B)和C)的問題 您是說我們讀取4mb數據塊並將其存儲在預先分配的緩衝區中,然後讀取緩衝區以將數據轉換爲記錄,並使用另一個線程實際發送記錄? – KodeWarrior 2013-03-04 23:20:46

+0

用僞代碼更新了回覆,通過iPad很難做到。代碼不是開源的,但可能只能刪除關鍵部分,將檢查和建議。它是Windows C++,儘管很容易看到unix等價物(也許我需要刪除重疊的IO部分,它爲磁盤讀取發出多個異步IO,這是特定於Windows的) – rlb 2013-03-05 02:59:13