ทำไม "ls *" ใช้เวลานานกว่า "ls" มาก?


28

ฉันมีไฟล์สองสามไฟล์ในไดเรกทอรี:

$ ls | wc -l
9376

ใครช่วยอธิบายได้ว่าทำไมถึงมีความแตกต่างครั้งใหญ่ในการใช้งานls *และ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 *)
$

คำตอบ:


47

เมื่อคุณรันlsโดยไม่มีอาร์กิวเมนต์มันจะเปิดไดเรกทอรีอ่านเนื้อหาทั้งหมดเรียงลำดับและพิมพ์ออกมา

เมื่อคุณเรียกใช้ls *เป็นครั้งแรกขยายเชลล์*ซึ่งเป็นได้อย่างมีประสิทธิภาพเช่นเดียวกับสิ่งที่เรียบง่ายไม่สร้างเวกเตอร์ทะเลาะกับไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันและบริการโทรls จากนั้นจะต้องประมวลผลอาร์กิวเมนต์เวกเตอร์นั้นและสำหรับแต่ละอาร์กิวเมนต์และเรียกใช้¹ไฟล์เพื่อตรวจสอบว่ามีอยู่จริง จากนั้นก็จะพิมพ์ออกมาการส่งออกเช่นเดียวกับครั้งแรก (แบบง่าย) ทั้งการประมวลผลของเชลล์ของเวกเตอร์อาร์กิวเมนต์ที่มีขนาดใหญ่และอาจเกี่ยวข้องกับการจัดสรรหน่วยความจำจำนวนมากของบล็อกขนาดเล็กซึ่งอาจใช้เวลาสักครู่ อย่างไรก็ตามเนื่องจากมีน้อยและเวลา แต่จำนวนมากของเวลาส่วนใหญ่ของเวลาที่จะได้รับที่จะรอให้ดิสก์มากกว่าการใช้ CPU ทำจัดสรรหน่วยความจำlslsaccess(2)lslssysuserreal

แต่ละการเรียกไปaccess(2)จะต้องอ่าน inode ของไฟล์เพื่อรับข้อมูลการอนุญาต นั่นหมายถึงดิสก์อ่านและค้นหามากกว่าอ่านไดเรกทอรี ฉันไม่ทราบว่าการดำเนินการเหล่านี้มีราคาแพงเพียงใดใน GPFS ของคุณ แต่เนื่องจากการเปรียบเทียบที่คุณแสดงls -lซึ่งมีระยะเวลาการรันคล้ายกับกรณีไวด์การ์ดเวลาที่จำเป็นในการดึงข้อมูลไอโหนดจะปรากฏขึ้น หาก GPFS มีเวลาแฝงที่สูงกว่าระบบไฟล์โลคัลของคุณเล็กน้อยในการดำเนินการอ่านแต่ละครั้งเราคาดว่ามันจะเด่นชัดมากขึ้นในกรณีเหล่านี้

ความแตกต่างระหว่าง case wildcard และls -l50% สามารถอธิบายได้โดยการเรียงลำดับของ inodes บนดิสก์ หาก inodes ถูกจัดวางอย่างต่อเนื่องตามลำดับเดียวกับชื่อไฟล์ในไดเรกทอรีและls -lstat (2) ed ไฟล์ในลำดับไดเรกทอรีก่อนการเรียงลำดับls -lอาจเป็นไปได้ที่จะอ่าน inodes ส่วนใหญ่ในการกวาด ด้วย wildcard เชลล์จะเรียงลำดับชื่อไฟล์ก่อนส่งผ่านlsดังนั้นlsจะมีแนวโน้มที่จะอ่าน inodes ในลำดับที่แตกต่างกันเพิ่มการเคลื่อนไหวของหัวดิสก์มากขึ้น

ควรสังเกตว่าtimeผลลัพธ์ของคุณจะไม่รวมเวลาที่เชลล์ใช้เพื่อขยายสัญลักษณ์แทน

หากคุณต้องการดูว่าเกิดอะไรขึ้นให้ใช้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 หรือไม่)


2
คำตอบที่ดีฉันเพิ่งจะโพสต์ข้อความที่คล้ายกัน :) แต่ใช่ถูกต้องมันเกี่ยวกับประสิทธิภาพในการวนรอบlsมันสามารถถามระบบไฟล์ "สิ่งที่เป็นลูกของ inode สำหรับpwd" ที่ไหนก็ได้ls *มันต้องถามว่า "อะไรคือ children (และอะไรคือไฟล์) ของ inode a" ตามด้วย b, c, d, ฯลฯ
NJ

@NJ หนึ่งข้อความค้นหาและหลาย ๆ ข้อความเป็นบทสรุปที่ดี @camh: ขอบคุณสำหรับคำตอบรายละเอียด ฉันโพสต์ผลลัพธ์ls -lเช่นกัน (ยังคงน้อยกว่า 30 วินาทีls *)
เซบาสเตียน

ในฐานะที่เป็น @Sebastian camh กล่าวว่าls -lจะใช้เวลานานกว่าlsที่มันมีให้กับstat(2)แต่ละไฟล์ที่จะได้รับข้อมูลเกี่ยวกับการประทับเวลา / ข้อมูลเจ้าของ / สิทธิ์ ฯลฯ
นิวเจอร์ซีย์

6
อย่าลืม*globs ไปทุกรายการในไดเรกทอรีปัจจุบันที่ไม่ได้เริ่มต้นด้วยระยะเวลา - รวมทั้งชื่อของไดเรกทอรีย่อย ซึ่งจะเป็นls'ed
Shadur

@camh: ผมทดสอบอีกเล็กน้อย (ดูการแก้ไขของฉัน) และพบว่า: ls< ls -l< ls -l *< ls *(ฉันมักจะวิ่งมันสามครั้ง) ด้วยคำอธิบายของคุณฉันไม่เข้าใจว่าทำไมls -l *จะเร็วกว่าls *
เซบาสเตียน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.