Tại sao mà ls ls * khác lại mất nhiều thời gian hơn so với những người khác?


28

Tôi có một vài tập tin trong một thư mục:

$ ls | wc -l
9376

Bất cứ ai có thể giải thích tại sao có sự khác biệt lớn về thời gian trong việc sử dụng 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

được rồi, đây là một ví dụ quyết liệt và có thể được tăng cường vì thư mục nằm trên một hệ thống tệp song song chung (GPFS). Nhưng tôi cũng có thể thấy một sự chậm lại đáng kể trên một hệ thống tệp cục bộ.

CHỈNH SỬA:

$ 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

và tôi nên thêm rằng trong ví dụ của tôi không có thư mục con:

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

Câu trả lời:


47

Khi bạn chạy lsmà không có đối số, nó sẽ chỉ mở một thư mục, đọc tất cả nội dung, sắp xếp chúng và in chúng ra.

Khi bạn chạy ls *, đầu tiên shell sẽ mở rộng *, tương tự như những gì đơn giản lsđã làm, xây dựng một vectơ đối số với tất cả các tệp trong thư mục hiện tại và các cuộc gọi ls. lssau đó phải xử lý vectơ đối số đó và cho từng đối số và gọi access(2)tệp để kiểm tra sự tồn tại của nó. Sau đó, nó sẽ in ra đầu ra giống như đầu tiên (đơn giản) ls. Cả quá trình xử lý của shell của vectơ đối số lớn và lscó thể sẽ liên quan đến việc phân bổ bộ nhớ cho các khối nhỏ, có thể mất một thời gian. Tuy nhiên, vì có rất ít sysuserthời gian, nhưng rất nhiều realthời gian, hầu hết thời gian sẽ bị gian chờ đợi cho đĩa, thay vì sử dụng CPU làm cấp phát bộ nhớ.

Mỗi cuộc gọi đến access(2)sẽ cần đọc inode của tập tin để có được thông tin cho phép. Điều đó có nghĩa là rất nhiều đĩa đọc và tìm kiếm hơn là chỉ đọc một thư mục. Tôi không biết các thao tác này đắt như thế nào trên GPFS của bạn, nhưng khi so sánh bạn đã chỉ ra ls -lcó thời gian chạy tương tự với trường hợp ký tự đại diện, thời gian cần thiết để lấy thông tin inode dường như chiếm ưu thế. Nếu GPFS có độ trễ cao hơn một chút so với hệ thống tệp cục bộ của bạn trên mỗi thao tác đọc, chúng tôi hy vọng nó sẽ rõ rệt hơn trong những trường hợp này.

Sự khác biệt giữa trường hợp ký tự đại diện và ls -l50% có thể được giải thích bằng cách sắp xếp các nút trên đĩa. Nếu các nút được đặt liên tiếp theo thứ tự như tên tệp trong thư mục và ls -lstat (2) ed các tệp theo thứ tự thư mục trước khi sắp xếp, ls -lcó thể sẽ đọc hầu hết các nút trong quá trình quét. Với ký tự đại diện, trình bao sẽ sắp xếp tên tệp trước khi chuyển chúng sang ls, do đó lscó thể sẽ đọc các nút theo thứ tự khác, thêm chuyển động đầu đĩa.

Cần lưu ý rằng timeđầu ra của bạn sẽ không bao gồm thời gian của trình bao để mở rộng ký tự đại diện.

Nếu bạn thực sự muốn xem những gì đang xảy ra, hãy sử dụng strace(1):

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

và có một cái nhìn mà các cuộc gọi hệ thống đang được thực hiện trong từng trường hợp.

Tôi không biết nếu access(2)thực sự được sử dụng, hoặc một cái gì đó khác như stat(2). Nhưng cả hai có lẽ yêu cầu tra cứu inode (Tôi không chắc liệu access(file, 0)có bỏ qua tra cứu inode không.)


2
Câu trả lời hay, tôi vừa mới đăng một bài tương tự :) Nhưng vâng, điều này đúng, tất cả là về tính hiệu quả trong vòng lặp, với lsnó chỉ có thể hỏi hệ thống tập tin "những đứa trẻ của inode là gì pwd" ls *nó phải hỏi "những đứa trẻ (và tập tin) của inode là gì a" theo sau là b, c, d, v.v. Một truy vấn so với nhiều.
NJ

@NJ một truy vấn so với nhiều là một tóm tắt tốt cho đến nay. @camh: cảm ơn câu trả lời chi tiết. Tôi cũng đã đăng kết quả đầu ra ls -l(vẫn còn ít hơn khoảng 30 giây ls *)
Sebastian

@Sebastian Như camh đã nêu, ls -lsẽ mất nhiều thời gian hơn so lsvới stat(2)từng tệp để nhận thông tin về dấu thời gian / thông tin chủ sở hữu / quyền, v.v.
NJ

6
Đừng quên, *ảm đạm cho tất cả các mục trong thư mục hiện tại không bắt đầu bằng một khoảng thời gian - bao gồm tên của các thư mục con. Mà sau đó sẽ là ls'ed.
Shadur

@camh: Tôi đã thử nghiệm hơn một chút (xem sửa của tôi) và thấy rằng: ls< ls -l< ls -l *< ls *(Tôi luôn luôn chạy nó ba lần). Với lời giải thích của bạn, tôi không hiểu tại sao ls -l *nhanh hơnls *
Sebastian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.