為什麼上​​廁所這麼慢?

為什麼上​​廁所這麼慢?

為什麼 wc 實用程式這麼慢?

當我在大檔案上運行它時,它花費的時間比 md5sum 長大約 20 倍:

MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s

MyDesktop:/tmp$ time wc /tmp/bigfile 
         0          0 1073741824 /tmp/bigfile

real    0m45.969s
user    0m45.424s
sys     0m0.424s

MyDesktop:/tmp$ time md5sum /tmp/bigfile 
cd573cfaace07e7949bc0c46028904ff  /tmp/bigfile

real    0m2.520s
user    0m2.196s
sys     0m0.316s

這不僅僅是由於文件充滿空值而導致的奇怪邊緣條件,即使文件充滿隨機數據或者是文字文件,我也看到了相同的性能差異。

(這是在 Ubuntu 13.04,64 位元上)

答案1

所以我去了原始碼,看起來緩慢是在處理雙位元組字元時。本質上,對於讀入的每個字符,都需要調用mbrtowc()嘗試將其轉換為寬字符,然後測試該寬字符以查看它是否是單字分隔符、行分隔符等。

事實上,如果我更改LANG預設的語言環境變數en_US.UTF-8(UTF-8 是多位元組字元集)並將其設定為“ C”(簡單的單字節字元集),wc則能夠使用單字節優化,從而大大加快速度,只需要以前的四分之一左右的時間。

此外,它只需檢查每個字元是否進行單字 ( -w)、行長度 ( -L) 或字元 ( -m) 計數。如果它只進行位元組和/或行計數,它可以跳過寬字元處理,然後運行得非常快——比md5sum.

我運行了它gprof,用於處理多字節字元(mymbsinit()mymbrtowc()myiswprint()等)的函數僅佔用了大約 30% 的執行時間,並且單步執行緩衝區的程式碼要複雜得多,因為它必須處理可變大小字符在緩衝區中的可變大小步驟,以及將跨越緩衝區的任何部分完成的字元填入緩衝區的開頭,以便下次可以處理它。

現在我知道要尋找什麼了,我發現了一些帖子提到一些實用程式的 utf-8 速度慢:

https://stackoverflow.com/questions/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/blogs/brendan/2011/12/08/2000x-performance-win/

答案2

只是一個猜測,但你有點將蘋果與橘子進行比較,比較wc正在做什麼和md5sum正在做什麼。

md5sum的任務

md5sum處理文件時,它只是將文件作為流打開,然後開始通過MD5校驗功能需要很少的內存。它本質上是 CPU 和磁碟 I/O 限制。

廁所的任務

wc運行時,它會做更多的事情,而不僅僅是一次解析文件一個字元。它必須實際分析文件的結構,一次一行地確定字元之間的邊界在哪裡以及是否是單字邊界。

例子

考慮以下字串以及每種演算法在解析它們時必須如何遍歷它們:

“Hello! Greg”
“Hello!Greg”
“Hello\nGreg”
“A.D.D.”
“Wow, how great!”
“wow     \n\n\n    great”
“it was a man-eating shark.”

對於 MD5,它每次在這些字串中移動一個字元。因為wc它必須決定什麼是單字和行邊界並追蹤它看到的出現次數。

其他廁所討論

我找到了這個2006 年的程式設計挑戰討論wc在 .NET 中的實作。當您查看一些偽代碼時,困難是非常明顯的,因此這可能有助於開始闡明為什麼wc看起來比其他操作慢得多。

相關內容