क्यों `खोजता है -टाइप f` को `find .` से अधिक समय लगता है।


15

ऐसा लगता है कि यह 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 पर

यहाँ पेर्ल स्क्रिप्ट का उपयोग मैंने बेंचमार्किंग के लिए किया है

#!/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
ऐसा लगता है कि यह findजांचना होगा कि क्या किसी दिए गए मार्ग को किसी भी तरह से फ़ाइल या निर्देशिका से मेल खाती है ताकि निर्देशिका की सामग्री को पुन: प्राप्त करने के लिए चल सके। - अगर यह एक निर्देशिका है, तो यह जांचना होगा कि क्या यह एक फ़ाइल है या नहीं। अन्य प्रवेश प्रकार हैं: नामित पाइप, प्रतीकात्मक लिंक, विशेष उपकरणों को ब्लॉक करें, सॉकेट ... इसलिए हो सकता है कि यह पहले से ही यह देखने के लिए चेक किया हो कि क्या यह एक निर्देशिका है, इसका मतलब यह नहीं है कि यह जानता है कि क्या यह एक नियमित फ़ाइल है।
रियल सेप्टिक

4,3k dirs और 2,8k फ़ाइलों के साथ यादृच्छिक निर्देशिका पर लागू होता है, -type fइसके बिना और इसके बिना एक ही समय पर चलता है। लेकिन पहली बार लिनक्स कर्नेल ने इसे कैश में लोड किया और बहुत पहले पता चला कि यह धीमा है।

1
मेरा पहला अनुमान है कि था -type fविकल्प की वजह से findकॉल करने के लिए stat()या fstat()या जो कुछ भी क्रम में पता लगाने के लिए यदि फ़ाइल नाम एक फ़ाइल के अनुरूप था, निर्देशिका, एक सिमलिंक, आदि आदि मैं एक किया था straceएक पर find . है और एक find . -type fऔर ट्रेस लगभग समान था, केवल उन write()कॉलों में अंतर करना जिनके पास निर्देशिका नाम थे। इसलिए, मुझे नहीं पता, लेकिन मैं इसका जवाब जानना चाहता हूं।
ब्रूस एडिगर

1
वास्तव में आपके प्रश्न का उत्तर नहीं है, लेकिन यह देखने के लिए एक timeअंतर्निहित कमांड है कि कमांड को निष्पादित करने में कितना समय लगता है, आपको वास्तव में परीक्षण करने के लिए एक कस्टम स्क्रिप्ट लिखने की आवश्यकता नहीं थी।
एलरंड

जवाबों:


16

GNU खोज में एक अनुकूलन है जिसे लागू किया जा सकता है, find .लेकिन इसके लिए नहीं find . -type f: यदि यह जानता है कि किसी निर्देशिका में शेष प्रविष्टियाँ निर्देशिका नहीं हैं, तो यह फ़ाइल प्रकार ( statसिस्टम कॉल के साथ) निर्धारित करने के लिए परेशान नहीं करता है जब तक कि एक न हो खोज मानदंड की आवश्यकता है। कॉलिंग statसमय-समय पर मापने योग्य समय ले सकती है क्योंकि जानकारी आमतौर पर इनोड में होती है, डिस्क पर एक अलग स्थान में, बजाय निर्देशिका में।

यह कैसे पता चलता है? क्योंकि एक निर्देशिका पर लिंक गिनती इंगित करती है कि उसके पास कितने उपनिर्देशिका हैं। विशिष्ट यूनिक्स फाइल सिस्टम पर, एक निर्देशिका की लिंक गणना 2 प्लस निर्देशिकाओं की संख्या होती है: एक निर्देशिका में अपने माता-पिता की .प्रविष्टि के लिए, एक प्रविष्टि के लिए, और ..प्रत्येक उपनिर्देशिका में प्रविष्टि के लिए एक ।

-noleafविकल्प बताता है findइस अनुकूलन लागू करने के लिए नहीं। यह उपयोगी है अगर findकुछ फाइलसिस्टम पर लागू किया जाता है जहां निर्देशिका लिंक की गिनती यूनिक्स सम्मेलन का पालन नहीं करती है।


क्या यह अभी भी उचित है? findस्रोत को देखते हुए , यह आजकल केवल कॉल fts_open()और fts_read()कॉल का उपयोग करता है।
रियलसेप्टिक

@RealSkeptic हाल के संस्करणों में बदल गया है? मैंने स्रोत की जाँच नहीं की है, लेकिन प्रयोगात्मक रूप से, डेबियन स्थिर में संस्करण 4.4.2 statतब कॉल को ऑप्टिमाइज़ करता है, जब उसे निर्देशिका लिंक काउंट्स के कारण उनकी आवश्यकता नहीं होती है, और -noleafविकल्प मैनुअल में दर्ज़ किया जाता है।
गिल्स एसओ- बुराई को रोकना '

यह संस्करण statमें भी अनुकूलन करता है fts...- यह उस fts_openकॉल के लिए उपयुक्त ध्वज को पास करता है । लेकिन मुझे यकीन नहीं है कि अभी भी प्रासंगिक है लिंक की संख्या के साथ जांच है। इसके बजाय यह जाँच करता है कि क्या दिए गए fts रिकॉर्ड में "निर्देशिका" झंडे में से एक है। यह हो सकता है कि fts_readस्वयं उस ध्वज को सेट करने के लिए लिंक की जाँच करता हो , लेकिन findऐसा नहीं करता। आप देख सकते हैं कि आपका संस्करण ftsकॉल करके निर्भर करता है या नहीं find --version
रियलसेप्टिक

@Gilles; findसैद्धांतिक रूप से यह निर्धारित करने में सक्षम होगा कि जब एक निर्देशिका में सभी प्रविष्टियाँ निर्देशिकाएं हैं और उस जानकारी का उपयोग करें?
ग्रेगरी निस्बेट

@GregoryNisbet सिद्धांत रूप में हाँ, लेकिन स्रोत कोड (मैंने अब जाँच की है) ऐसा नहीं करता है, संभवतः क्योंकि यह बहुत दुर्लभ मामला है।
गिलेस एसओ- बुराई को रोकना '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.