Vypadá to jako find
musel by stejně zkontrolovat, zda daná cesta odpovídá souboru nebo adresáři, aby mohl rekurzivně projít obsah adresářů.
Zde je určitá motivace a to, co jsem udělal lokálně, abych se přesvědčil, že find . -type f
je opravdu pomalejší než find .
. Ještě jsem se nehrabal ve zdrojovém kódu GNU find.
Takže zálohuji některé soubory v mém $HOME/Workspace
adresář a vyjma souborů, které jsou buď závislostmi mých projektů, nebo soubory správy verzí.
Spustil jsem tedy následující příkaz, který se rychle provedl
% find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-and-dirs.txt
find
přesměrováno do grep
může být špatná forma, ale zdálo se to jako nejpřímější způsob použití filtru negovaného regulárního výrazu.
Následující příkaz obsahuje pouze soubory ve výstupu find a trval znatelně déle.
% find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-only.txt
Napsal jsem nějaký kód, abych otestoval výkon těchto dvou příkazů (s dash
a tcsh
, jen abychom vyloučili jakékoli účinky, které by shell mohl mít, i když by žádné neměly být). tcsh
výsledky byly vynechány, protože jsou v podstatě stejné.
Výsledky, které jsem dostal, ukázaly asi 10% penalizaci výkonu pro -type f
Zde je výstup programu ukazující množství času potřebného k provedení 1000 iterací různých příkazů.
% 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
Testováno pomocí
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Na Ubuntu 15.10
Zde je skript perl, který jsem použil pro srovnávání
#!/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);
}
}
Přijatá odpověď:
GNU find má optimalizaci, kterou lze použít na find .
ale ne k find . -type f
:pokud ví, že žádná ze zbývajících položek v adresáři nejsou adresáře, pak se neobtěžuje určit typ souboru (pomocí stat
systémové volání), pokud to jedno z vyhledávacích kritérií nevyžaduje. Volání stat
může trvat měřitelný čas, protože informace jsou obvykle v inodu, na samostatném místě na disku, nikoli v adresáři, který obsahuje.
jak to ví? Protože počet odkazů na adresář udává, kolik podadresářů má. Na typických unixových souborových systémech je počet odkazů na adresář 2 plus počet adresářů:jeden pro záznam adresáře v jeho rodiči, jeden pro .
záznam a jeden pro ..
záznam v každém podadresáři.
-noleaf
volba říká find
tuto optimalizaci nepoužít. To je užitečné, pokud find
je vyvolán na některých souborových systémech, kde počty odkazů na adresáře neodpovídají unixové konvenci.