`find.-type f`가 `find .`보다 오래 걸리는 이유는 무엇입니까?

`find.-type f`가 `find .`보다 오래 걸리는 이유는 무엇입니까?

find디렉토리의 내용을 재귀적으로 탐색하려면 주어진 경로가 파일이나 디렉토리에 해당하는지 확인해야 하는 것 같습니다 .

find . -type f여기에 몇 가지 동기가 있으며 그것이 실제로 그것보다 낫다는 것을 스스로 확신하기 위해 로컬에서 수행한 작업은 find .아직 GNU 찾기 소스 코드를 조사하지 않았습니다.

그래서 디렉터리의 일부 파일을 백업 $HOME/Workspace하고 프로젝트 종속성 또는 버전 제어 파일인 파일은 제외했습니다.

그래서 빠르게 실행되는 다음 명령을 실행했습니다.

% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt

find파이핑은 grep아마도 나쁜 형식일 수 있지만 부정적인 정규식 필터를 사용하는 가장 간단한 방법인 것 같습니다.

다음 명령은 찾기 출력의 파일만 포함하므로 훨씬 더 오래 걸립니다.

% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt

나는 이 두 명령의 성능을 테스트하기 위해 몇 가지 코드를 작성했습니다( dash및 를 사용하여 tcsh쉘이 가질 수 있는 영향을 배제하기 위해). 결과는 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

시험용

% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.

우분투 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);
    }
}

답변1

find .GNU find에는 적용할 수 있지만 적용할 수 없는 최적화가 있습니다 . 디렉터리의 나머지 항목 중 어느 것도 디렉터리가 아니라는 것을 알고 있으면 검색 중 하나가 아닌 한 find . -type f(시스템 호출을 사용하여) 파일 형식을 결정하지 않습니다. stat조건이 필요합니다. stat정보는 일반적으로 포함된 디렉터리가 아닌 디스크의 별도 위치에 있는 inode에 있기 때문에 호출에 꽤 오랜 시간이 걸릴 수 있습니다.

어떻게 알 수 있나요? 디렉토리의 링크 수는 해당 디렉토리에 있는 하위 디렉토리 수를 나타내기 때문입니다. 일반적인 Unix 파일 시스템에서 디렉터리의 링크 수는 2에 디렉터리 수를 더한 값입니다. 상위 디렉터리의 디렉터리 항목은 1, 각 하위 디렉터리의 항목은 1 , 각 하위 디렉터리의 항목은 .1입니다 ...

-noleaf옵션은 find이 최적화가 적용되지 않아야 함을 나타냅니다. 이는 find디렉터리 링크 계산이 Unix 규칙을 따르지 않는 특정 파일 시스템에서 호출되는 경우 유용합니다.

관련 정보