ls
thực sự sắp xếp các tệp và cố gắng liệt kê chúng trở thành một chi phí khổng lồ nếu chúng ta đang cố gắng liệt kê hơn một triệu tệp trong một thư mục. Như đã đề cập trong liên kết này , chúng tôi có thể sử dụng strace
hoặc find
liệt kê các tệp. Tuy nhiên, những tùy chọn đó cũng có vẻ không khả thi đối với vấn đề của tôi vì tôi có 5 triệu tệp. Sau một chút loay hoay, tôi thấy rằng nếu chúng tôi liệt kê các thư mục sử dụng getdents()
, nó được cho là nhanh hơn, bởi vì ls
, find
và Python
các thư viện sử dụng readdir()
chậm hơn nhưng sử dụng getdents()
bên dưới.
Chúng tôi có thể tìm mã C để liệt kê các tệp bằng cách sử dụng getdents()
từ đây :
/*
* List directories using getdents() because ls, find and Python libraries
* use readdir() which is slower (but uses getdents() underneath.
*
* Compile with
* ]$ gcc getdents.c -o getdents
*/
#define _GNU_SOURCE
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE 1024*1024*5
int
main(int argc, char *argv[])
{
int fd, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
d_type = *(buf + bpos + d->d_reclen - 1);
if( d->d_ino != 0 && d_type == DT_REG ) {
printf("%s\n", (char *)d->d_name );
}
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS);
}
Sao chép chương trình C ở trên vào thư mục chứa các tệp cần được liệt kê. Sau đó thực hiện các lệnh dưới đây.
gcc getdents.c -o getdents
./getdents
Ví dụ về thời gian : getdents
có thể nhanh hơn nhiều ls -f
, tùy thuộc vào cấu hình hệ thống. Dưới đây là một số thời gian biểu thị tốc độ tăng 40 lần để liệt kê một thư mục chứa khoảng 500k tệp trên giá trị NFS trong cụm tính toán. Mỗi lệnh được chạy 10 lần liên tiếp, đầu tiên getdents
, sau đó ls -f
. Lần chạy đầu tiên chậm hơn đáng kể so với tất cả những lần khác, có thể là do lỗi trang bộ nhớ đệm NFS. (Ngoài ra: trên giá trị này, d_type
trường không đáng tin cậy, theo nghĩa là nhiều tệp xuất hiện dưới dạng "không xác định".)
command: getdents $bigdir
usr:0.08 sys:0.96 wall:280.79 CPU:0%
usr:0.06 sys:0.18 wall:0.25 CPU:97%
usr:0.05 sys:0.16 wall:0.21 CPU:99%
usr:0.04 sys:0.18 wall:0.23 CPU:98%
usr:0.05 sys:0.20 wall:0.26 CPU:99%
usr:0.04 sys:0.18 wall:0.22 CPU:99%
usr:0.04 sys:0.17 wall:0.22 CPU:99%
usr:0.04 sys:0.20 wall:0.25 CPU:99%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
command: /bin/ls -f $bigdir
usr:0.53 sys:8.39 wall:8.97 CPU:99%
usr:0.53 sys:7.65 wall:8.20 CPU:99%
usr:0.44 sys:7.91 wall:8.36 CPU:99%
usr:0.50 sys:8.00 wall:8.51 CPU:100%
usr:0.41 sys:7.73 wall:8.15 CPU:99%
usr:0.47 sys:8.84 wall:9.32 CPU:99%
usr:0.57 sys:9.78 wall:10.36 CPU:99%
usr:0.53 sys:10.75 wall:11.29 CPU:99%
usr:0.46 sys:8.76 wall:9.25 CPU:99%
usr:0.50 sys:8.58 wall:9.13 CPU:99%
ls
việc sử dụng--color
hoặc-F
điều đó có nghĩa là thực hiện mộtlstat(2)
cho mỗi tệp.