Filesystems

為什麼“ls *”比“ls”花費的時間長這麼多?

  • May 5, 2011

我在一個目錄中有幾個文件:

$ ls | wc -l
9376

任何人都可以解釋為什麼使用ls *and有如此大的時間差異ls嗎?

$ time ls > /dev/null
real    0m0.118s
user    0m0.106s
sys     0m0.011s

$ time ls * > /dev/null
real    1m32.602s
user    0m0.233s
sys     0m0.438s

好的,這是一個極端的範例,並且可能會增強,因為該目錄位於通用並行文件系統 (GPFS) 上。但我也可以看到本地文件系統的速度明顯下降。

編輯:

$ time ls -l > /dev/null
real    0m58.772s
user    0m0.113s
sys     0m0.452s
$ time ls -l * > /dev/null
real    1m19.538s
user    0m0.252s
sys     0m0.461s

我應該補充一點,在我的範例中沒有子目錄:

$ diff <(ls) <(ls *)
$

當你ls不帶參數執行時,它只會打開一個目錄,讀取所有內容,對它們進行排序並列印出來。

當你執行時ls *,首先 shell 擴展*,這實際上與 simplels所做的相同,使用目前目錄中的所有文件建構一個參數向量並呼叫ls. ls然後必須處理該參數向量和每個參數,並呼叫access(2)¹ 文件來檢查它的存在。然後它將列印出與第一個 (simple) 相同的輸出ls。shell 對大參數向量的處理和ls’s 都可能涉及到小塊的大量記憶體分配,這可能需要一些時間。但是,由於時間少sysuser時間多real,所以大部分時間都會花在等待磁碟上,而不是用CPU做記憶體分配。

每次呼叫access(2)都需要讀取文件的 inode 以獲取權限資訊。這意味著比簡單地讀取目錄要多得多的磁碟讀取和查找。我不知道這些操作在您的 GPFS 上的成本有多大,但是作為您所展示的比較,ls -l它與萬用字元情況具有相似的執行時間,檢索 inode 資訊所需的時間似乎占主導地位。如果 GPFS 在每次讀取操作時的延遲都比本地文件系統稍高,我們預計在這些情況下它會更加明顯。

萬用字元大小寫和 50% 之間的差異ls -l可以通過磁碟上 inode 的順序來解釋。如果 inode 以與目錄中的文件名相同的順序連續排列,並ls -l在排序之前按目錄順序對文件進行 stat(2),則ls -l可能會一次讀取大部分 inode。使用萬用字元,shell 將在將文件名傳遞給之前對文件名進行排序ls,因此ls可能會以不同的順序讀取 inode,從而增加更多的磁碟磁頭移動。

應該注意的是,您的time輸出將不包括 shell 擴展萬用字元所花費的時間。

如果你真的想看看發生了什麼,請使用strace(1)

strace -o /tmp/ls-star.trace ls *
strace -o /tmp/ls-l-star.trace ls -l *

並查看每種情況下正在執行哪些系統呼叫。

¹我不知道是否access(2)實際使用過,或者其他諸如stat(2). 但兩者都可能需要 inode 查找(我不確定是否access(file, 0)會繞過 inode 查找。)

引用自:https://unix.stackexchange.com/questions/12659