2012-07-19 163 views
9

我仍然經常使用控制檯輸出來瞭解我的代碼中發生了什麼。 我知道這可能是有點老的時尚,但我也用這個來「管」標準輸出 到日誌文件等C:爲什麼fprintf(stdout,....)這麼慢?

然而,事實證明,輸出到控制檯減慢一些 原因。我想知道是否有人可以解釋爲什麼fprintf()到控制檯 窗口似乎有點阻塞。

我做了什麼/到目前爲止診斷:

  1. 我測量的時候一個簡單的 fprintf(stdout,"quick fprintf\n"); 它的需要:0.82ms(平均)。由於vsprintf_s(...)在幾微秒內將相同的輸出寫入字符串,這被認爲太長了。因此,必須專門爲控制檯設置一些阻止。

  2. 爲了避免阻塞,我使用了vsprintf_s(...)將我的輸出複製到類似於fifo的數據結構中。數據結構受臨界區對象保護。然後,一個單獨的線程通過將排隊的輸出放入控制檯來解除數據結構。

  3. 我可以通過引入管道服務獲得進一步的改進。 我的程序(應該在控制檯窗口結束)的輸出變爲通過以下方式:

    • 一個vsprintf_s(...)格式輸出,以簡單的字符串。
    • 這些字符串排隊成一個類似於fifo的數據結構,例如鏈表結構。該數據結構受臨界區對象保護。
    • 第二個線程通過將輸出字符串發送到命名管道來使數據結構出列。
    • 第二個進程讀取命名管道,並將這些字符串再次放入類似於FIFO的數據結構中。這是爲了讓讀數遠離控制檯的阻塞輸出。 讀取命名管道的讀取過程非常快,並且持續監視管道緩衝區的填充水平。
    • 第二個進程中的第二個線程最終將數據結構出隊fprintf(stdout,...)到控制檯。

所以我有在管的兩側上的兩個過程,每個至少有兩個線程,它們之間的命名管道,和FIFO一樣的數據結構,以避免在管道緩衝區滿的情況下,阻斷。

這是很多東西,只是要確保控制檯輸出是「非阻塞」。但結果是 不算太壞。我的主程序可以在幾微秒內寫入複雜的fprintf(stdout,...)。

也許我應該問早些時候:有沒有其他(更簡單!)的方式來實現無阻塞控制檯輸出?

+6

我懷疑它是緩慢的控制檯。終端仿真器往往很慢(因爲它們的波特率是其規格的一部分)。你只是測量將* stdout *重定向到某個文件的時間?你可以輸出調試信息給其他'FILE'(並使用帶有大緩衝區的'setvbuf')。 – 2012-07-19 10:13:05

+0

什麼操作系統,庫,編譯器,你正在使用? – 2012-07-19 10:15:33

+0

如果您不知道等待輸出通道花費了多少時間,那麼'fprintf'花費的時間量並不是非常有趣。 – 2012-07-19 10:17:05

回答

12

我認爲時間問題與事實,控制檯是行緩衝默認情況下。這意味着每次你寫一個'\n'字符時,你的整個輸出緩衝區都會被髮送到控制檯,這是一個相當昂貴的操作。這是您爲該行立即出現在輸出中而付出的代價。

您可以通過將緩衝策略更改爲完全緩衝來更改此默認行爲。結果是輸出將以等於緩衝區大小的塊形式發送到控制檯,但單個操作將更快完成。

撥打這個電話之前,你先寫控制檯:

char buf[10000]; 
setvbuf(stdout, buf, _IOFBF, sizeof(buf)); 

個人寫的時間應提高,但產量不會立即出現在控制檯中。這對調試並不是很有用,但時間會改善。如果你設置一個定期調用fflush(stdout)的線程,比如說每秒一次,你應該在單個寫入的性能和寫入輸出的程序之間的延遲和你實際看到它的時間之間取得合理的平衡在控制檯上。

+0

測試,確認,很好的答案。我希望有一些技巧可以加快速度 – Arno 2012-07-19 10:48:53

+0

當然,這應該使用'sizeof buf'而不是重複魔術常數。 :) – unwind 2012-07-19 11:09:30

+0

@unwind當然,你是對的!這是我的一個顯而易見的遺漏,當你看到我做這樣愚蠢的事情時,歡迎編輯我的答案:)非常感謝! – dasblinkenlight 2012-07-19 11:17:41