Neden bulur? -f tipi "bul" dan daha uzun sürüyor mu?


15

findDizinlerin içeriğini yinelemeli olarak yürütebilmek için belirli bir yolun bir dosyaya veya dizine karşılık gelip gelmediğini kontrol etmek gibi görünüyor .

İşte biraz motivasyon ve kendimi find . -type fdaha yavaş olduğuna ikna etmek için yerel olarak yaptığım şey find .. Henüz GNU bulma kaynak koduna girmedim.

Bu yüzden dizinimdeki bazı dosyaları yedekliyorum $HOME/Workspaceve projelerimin veya sürüm kontrol dosyalarının bağımlılığı olan dosyaları hariç tutuyorum.

Bu yüzden hızlı bir şekilde yürütülen aşağıdaki komutu çalıştırdım

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

findborulu grepolabilir, ancak olumsuz bir normal ifade filtresi kullanmanın en doğrudan yolu gibi görünüyordu.

Aşağıdaki komut yalnızca find çıktısındaki dosyaları içerir ve fark edilir şekilde daha uzun sürdü.

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

Bu iki komutun performansını test etmek için bazı kodlar yazdım ( dashve tcsh, herhangi bir olmamasına rağmen kabuğun sahip olabileceği herhangi bir etkiyi ekarte etmek için). tcshOnlar temelde aynı çünkü sonuçlar atlanmıştır.

Aldığım sonuçlar% 10 performans cezası gösterdi -type f

İşte çeşitli komutların 1000 yinelemesini yürütmek için geçen süreyi gösteren program çıktısı.

% 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

İle test edildi

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

Ubuntu 15.10

Kıyaslama için kullandığım perl betiği

#!/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);
    }
}

2
findDizinlerin içeriğini yinelemeli olarak yürütebilmek için belirli bir yolun bir dosyaya veya dizine karşılık gelip gelmediğini kontrol etmek gibi görünüyor . - bir dizin olup olmadığını kontrol etmek zorunda kalacak, bir dosya olup olmadığını kontrol etmek zorunda olmayacaktı. Başka giriş türleri de var: adlandırılmış borular, sembolik bağlantılar, özel aygıtları engelle, soketler ... Bu nedenle, bir dizin olup olmadığını görmek için kontrolü yapmış olsa da, normal bir dosya olup olmadığını bildiği anlamına gelmez.
RealSkeptic

Meşgul kutusu bulma, 4,3k dirs ve 2,8k dosyaları ile rastgele dizine uygulanan ve onsuz aynı anda çalışır -type f. Ancak Linux çekirdeği ilk defa önbelleğe yükledi ve ilk bulma işlemi daha yavaştı.

1
İlk tahminim olmasıydı -type fseçenek sebep findaramak stat()veya fstat()dosya adı bir dosyaya karşılık öğrenmek için ya da her türlü sırayla, vb vb ben yaptım bir dizin, bir sembolik stracebir üstünde find . ve find . -type fve iz neredeyse aynıydı, yalnızca içinde write()dizin adları olan aramalarda farklılık gösterir . Yani bilmiyorum, ama cevabı bilmek istiyorum.
Bruce Ediger

1
Sorunuza gerçekten bir cevap değil, ancak timebir komutun yürütülmesinin ne kadar sürdüğünü görmek için yerleşik bir komut var, gerçekten test etmek için özel bir komut dosyası yazmanıza gerek yoktu.
Elronnd

Yanıtlar:


16

GNU bulmak için uygulanabilecek bir optimizasyonu var find .ama değil find . -type f: Bir dizinde kalan girişlerin hiçbirinin biliyorsa dizinleri vardır, o zaman (dosya türünü belirlemek için rahatsız etmez statbiri olmadıkça sistem çağrısı) arama kriterleri bunu gerektirir. statBilgiler tipik olarak inode içinde, içerdiği dizinde değil, diskte ayrı bir yerde bulunduğundan, arama ölçülebilir bir zaman alabilir.

Nasıl biliyor? Çünkü bir dizindeki bağlantı sayısı kaç alt dizine sahip olduğunu gösterir. Tipik Unix dosya sistemlerinde, bir dizinin bağlantı sayısı 2 artı dizin sayısıdır: biri dizinin üst öğesindeki .girişi için, biri giriş için ve diğeri ..her alt dizindeki giriş için .

-noleafSeçenek söyler findbu optimizasyon uygulamama. Bu, finddizin bağlantı sayılarının Unix kuralına uymadığı bazı dosya sistemlerinde çağrıldığında faydalıdır .


Bu hala geçerli mi? findKaynağa baktığımızda, günümüzde sadece fts_open()ve fts_read()çağrılarını kullanıyor .
RealSkeptic

@RealSkeptic Bu son sürümlerde değişti mi? Kaynağı kontrol etmedim, ancak deneysel olarak Debian kararlı sürüm 4.4.2, statdizin bağlantı sayıları nedeniyle ihtiyaç duymadığında aramaları optimize ediyor ve -noleafseçenek kılavuzda belgeleniyor.
Gilles 'SO- kötü olmayı

Versiyonda statbile optimizasyon yapar fts...- bunun için uygun bayrağı fts_openaramaya geçirir . Ama emin değilim hala ilgili bağlantı sayısı ile kontrol. Bunun yerine, döndürülen fts kaydının "dizin" bayraklarından birine sahip olup olmadığını denetler. Bu fts_readbayrağı ayarlamak için bağlantıları kontrol ediyor olabilir , ancak findyapmaz. Sürümünüzün güvenilip güvenilmediğini ftsarayarak görebilirsiniz find --version.
RealSkeptic

@Gilles, olur find Teorik olarak bir dizindeki tüm girdilerin ne zaman dizin olduğunu belirleyebilir ve bu bilgileri kullanabilir mi?
Gregory Nisbet

@GregoryNisbet Teoride evet, ancak kaynak kodu (şimdi kontrol ettim) muhtemelen bunu yapmıyor çünkü muhtemelen daha nadir bir durum.
Gilles 'SO- kötü olmayı bırak'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.