為什麼“ls *”比“ls”花費的時間長這麼多?
我在一個目錄中有幾個文件:
$ 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 都可能涉及到小塊的大量記憶體分配,這可能需要一些時間。但是,由於時間少sys
,user
時間多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 查找。)