2012-02-11 91 views
2

我無法優化C++程序以實現最快的運行時間。在C++中優化IO

該代碼的要求是輸出2個長整數的差值的絕對值,通過文件輸入到程序中。即:

./myprogram < unkownfilenamefullofdata 

文件名是未知的,每行有2個數字,用空格分隔。有一個未知數量的測試數據。我創建了2個測試數據文件。一個人有極端的情況,並且長達5次。至於另一個,我使用了一個Java程序來產生2,000,000個隨機數,並將其輸出到一個timedrun文件 - 18.MB的測試值。

海量文件運行時間爲3.4秒。我需要將其分解爲1.1秒。

這是我的代碼:

int main() { 
long int a, b; 
while (scanf("%li %li",&a,&b)>-1){ 
    if(b>=a) 
    printf("%li/n",(b-a)); 
    else 
    printf("%li/n",(a-b)); 
    } //endwhile 
return 0; 
}//end main 

我跑Valgrind的在我的計劃,而事實證明,很多滯留在讀取和寫入部分。如果我知道我只打算接收一個數字,我會如何將打印/掃描重寫爲最原始的C++格式?有沒有一種方法可以將數字掃描爲二進制數,並通過邏輯運算操作數據來計算差異?我也被告知要考慮寫一個緩衝區,但在搜索網頁6個小時後,嘗試執行代碼,我沒有成功。

任何幫助將不勝感激。

+0

您是否使用優化進行編譯? – Dave 2012-02-11 15:28:21

+0

重定向輸出。 – 2012-02-11 15:30:58

+1

您的程序不會讀取文件,您正在使用重定向將文件內容提供給程序。將文件直接加載到應用程序中,將其完全加載到內存中,然後找到比scanf更低級別的例程來解析它。 – 2012-02-11 15:32:09

回答

2

你需要做的是將整個字符串加載到內存中,然後從那裏提取數字,而不是重複進行I/O調用。但是,您可能發現,硬盤驅動器加載18MB只需要很長時間。

+2

合理的現代硬盤驅動器能夠讀取80-120 MB/s。這不是解釋所花費的時間。 – 2012-02-11 16:51:42

+0

@ BenVoigt:誰說他有合理的現代硬盤? – Puppy 2012-02-11 22:41:36

+0

你說得對。如果他關心性能,他可能有一個SATA-II SSD(200 MB/s)或一個SATA-III SSD(500 MB/s)。或熱文件系統緩存(多GB /秒)。 – 2012-02-12 01:15:27

1

您可以在scanf上大大提高,因爲您可以保證文件的格式。既然你確切地知道格式是什麼,你不需要多少錯誤檢查。此外,printf會將新行轉換爲您的平臺的適當換行符。

我已經使用了類似於這個SPOJ forum post中的代碼(請參閱nosy的後半部分),以在讀取整數區域獲得相當大的加速。你將需要修改它來處理負數。希望它能給你一些關於如何編寫更快的printf函數的想法,但是我會先從替換scanf開始,看看你得到了多少。

+0

用於整數的'printf' ='itoa' +'puts'。 'itoa'的優化版本[這裏](http://stackoverflow.com/questions/4351371/c-performance-challenge-integer-to-stdstring-conversion)。 – 2012-02-11 16:53:04

1

正如你所建議的問題是讀取所有這些數字和從文本轉換爲二進制。

最好的改進是將任何程序生成的數字寫成二進制。這將減少大量減少必須從磁盤讀取的數據量,並稍微縮短從文本轉換爲二進制文件所需的時間。

你說2,000,000個數字佔用18MB =每個數字9個字節。這包括空格和行標記的結尾,因此聽起來合理。

將數字存儲爲4個字節的整數將是必須從磁盤讀取的數據量的一半。除了節省格式轉換之外,期望性能翻一番是合理的。

由於您需要更多,需要更激進的東西。您應該考慮將數據文件拆分爲單獨的文件,每個文件位於各自的磁盤上,然後在各自的進程中處理每個文件。如果您擁有4個內核並將處理分成4個獨立進程並可連接4個高性能磁盤,那麼您可能希望將性能再提高一倍。現在瓶頸是操作系統磁盤管理,並且不可能猜測操作系統將如何並行管理四個磁盤。

我假設這是一個非常簡化的處理模型,你需要做的。如果你的描述是全部,那麼真正的解決方案就是在寫測試文件的程序中做減法運算!

+0

「最好的改進是把數字寫成二進制。」 <---這。 (嗯,這個和內存映射文件,而不是通過管道全部推送)。 – Damon 2012-02-13 11:09:33

0

甚至比在程序中打開文件並一次讀取所有文件更好的方法是使用內存映射。對於程序可用的〜2GB地址空間,〜18MB是沒有問題的。

然後使用strtod讀取一個數字並提前指針。

相比輸入重定向和scanf,我預計5-10倍加速。