Gre*_*bet 15 performance find gnu
似乎find必须检查给定的路径是否与文件或目录相对应,以便递归地遍历目录的内容。
这是一些动机以及我在本地所做的事情,以说服自己find . -type f确实比find .. 我还没有深入研究 GNU 查找源代码。
所以我正在备份我$HOME/Workspace目录中的一些文件,并排除属于我的项目或版本控制文件的依赖项的文件。
所以我运行了以下快速执行的命令
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
Run Code Online (Sandbox Code Playgroud)
find管道传输到grep可能是不好的形式,但它似乎是使用否定正则表达式过滤器的最直接方式。
以下命令仅包含 find 输出中的文件,并且花费的时间明显更长。
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
Run Code Online (Sandbox Code Playgroud)
我编写了一些代码来测试这两个命令的性能(使用dash和tcsh,只是为了排除 shell 可能产生的任何影响,即使不应该有任何影响)。的tcsh,因为他们基本上是相同的结果已被忽略。
我得到的结果显示了大约 10% 的性能损失 -type f
下面是程序的输出,显示了执行 1000 次各种命令迭代所花费的时间。
% 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
Run Code Online (Sandbox Code Playgroud)
测试过
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Run Code Online (Sandbox Code Playgroud)
在 Ubuntu 15.10 上
这是我用于基准测试的 perl 脚本
#!/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 "%s\n\n", time_command(@$shell, $command);
}
}
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 16
GNU find 有一个优化,可以应用于find .但不能应用于find . -type f:如果它知道目录中剩余的条目都不是目录,那么它不会费心确定文件类型(使用stat系统调用),除非其中之一搜索条件需要它。调用stat可能需要可测量的时间,因为信息通常位于 inode 中,位于磁盘上的单独位置,而不是包含目录中。
它怎么知道?因为目录上的链接数表示它有多少个子目录。在典型的 Unix 文件系统上,一个目录的链接数是 2 加上目录数:一个用于目录在其父目录中的条目,一个用于.条目,一个用于..每个子目录中的条目。
该-noleaf选项告诉find不要应用此优化。如果find在目录链接计数不遵循 Unix 约定的某些文件系统上调用,这将很有用。