Sepertinya find
harus memeriksa apakah jalur yang diberikan sesuai dengan file atau direktori untuk menelusuri konten direktori secara rekursif.
Berikut beberapa motivasi dan apa yang telah saya lakukan secara lokal untuk meyakinkan diri saya sendiri bahwa find . -type f
benar-benar lebih lambat dari find .
. Saya belum menggali kode sumber GNU find.
Jadi saya mencadangkan beberapa file di $HOME/Workspace
saya direktori, dan mengecualikan file yang merupakan dependensi proyek saya atau file kontrol versi.
Jadi saya menjalankan perintah berikut yang dieksekusi dengan cepat
% find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-and-dirs.txt
find
disalurkan ke grep
mungkin bentuk yang buruk, tetapi sepertinya cara paling langsung untuk menggunakan filter regex yang dinegasikan.
Perintah berikut hanya menyertakan file dalam output find dan membutuhkan waktu lebih lama.
% find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-only.txt
Saya menulis beberapa kode untuk menguji kinerja kedua perintah ini (dengan dash
dan tcsh
, hanya untuk mengesampingkan efek apa pun yang mungkin dimiliki shell, meskipun seharusnya tidak ada). tcsh
hasil telah dihilangkan karena pada dasarnya sama.
Hasil yang saya dapatkan menunjukkan tentang penalti kinerja 10% untuk -type f
Berikut adalah output dari program yang menunjukkan jumlah waktu yang dibutuhkan untuk mengeksekusi 1000 iterasi dari berbagai perintah.
% perl tester.pl
/bin/sh -c find Workspace/ >/dev/null
82.986582
/bin/sh -c find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > /dev/null
90.313318
/bin/sh -c find Workspace/ -type f >/dev/null
102.882118
/bin/sh -c find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > /dev/null
109.872865
Diuji dengan
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Di Ubuntu 15.10
Ini skrip perl yang saya gunakan untuk benchmarking
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw[gettimeofday tv_interval];
my $max_iterations = 1000;
my $find_everything_no_grep = <<'EOF';
find Workspace/ >/dev/null
EOF
my $find_everything = <<'EOF';
find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > /dev/null
EOF
my $find_just_file_no_grep = <<'EOF';
find Workspace/ -type f >/dev/null
EOF
my $find_just_file = <<'EOF';
find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > /dev/null
EOF
my @finds = ($find_everything_no_grep, $find_everything,
$find_just_file_no_grep, $find_just_file);
sub time_command {
my @args = @_;
my $start = [gettimeofday()];
for my $x (1 .. $max_iterations) {
system(@args);
}
return tv_interval($start);
}
for my $shell (["/bin/sh", '-c']) {
for my $command (@finds) {
print "@$shell $command";
printf "%snn", time_command(@$shell, $command);
}
}
Jawaban yang Diterima:
GNU find memiliki pengoptimalan yang dapat diterapkan ke find .
tetapi tidak untuk find . -type f
:jika mengetahui bahwa tidak ada entri yang tersisa dalam direktori adalah direktori, maka tidak perlu repot menentukan jenis file (dengan stat
panggilan sistem) kecuali salah satu kriteria pencarian memerlukannya. Memanggil stat
dapat memakan waktu yang terukur karena informasi biasanya ada di inode, di lokasi terpisah di disk, daripada di direktori yang memuatnya.
Bagaimana itu tahu? Karena jumlah tautan pada direktori menunjukkan berapa banyak subdirektori yang dimilikinya. Pada sistem file Unix biasa, jumlah tautan direktori adalah 2 ditambah jumlah direktori:satu untuk entri direktori di induknya, satu untuk .
entri, dan satu untuk ..
entri di setiap subdirektori.
-noleaf
opsi memberitahu find
untuk tidak menerapkan pengoptimalan ini. Ini berguna jika find
dipanggil pada beberapa sistem file di mana jumlah tautan direktori tidak mengikuti konvensi Unix.