Ik heb beide commandos geprobeerd en het commando find | grep "filename" is vele malen langzamer dan het simpele find "filename" commando.

Wat zou een goede verklaring zijn voor dit gedrag?

Reacties

  • Jij geven een lijst van elk bestand met find en geven de gegevens vervolgens door aan grep om te verwerken. Met find gebruikt erop ‘ eigen, mis je de stap van het doorgeven van elk weergegeven bestand aan grep om de uitvoer te ontleden. Dit zal daarom sneller gaan.
  • Langzamer in welke zin? Duurt het voltooien van de opdrachten een andere hoeveelheid tijd?
  • Ik kan dit ‘ niet lokaal reproduceren. time find "$HOME" -name '.profile' rapporteert in ieder geval een langere tijd dan time find "$HOME" | grep -F '.profile'. (17s vs. 12s).
  • @JenniferAnderson Ik heb beide herhaaldelijk gerend. De 17 en 12 seconden zijn gemiddelden. En ja, de grep -variant komt overal in het find -resultaat overeen, terwijl het matchen met find -name zou alleen exact overeenkomen (in dit geval).
  • Ja, find filename zou snel zijn . Ik nam een beetje aan dat dit een typfout was en dat het OP find -name filename betekende. Met find filename, zou alleen filename worden onderzocht (en niets anders).

Antwoord

(Ik “neem aan dat GNU find hier)

Alleen gebruiken

find filename 

zou snel zijn, omdat het alleen filename zou retourneren, of de namen binnen filename als het een map is, of een foutmelding als die naam niet bestond in de huidige map. Het “is een zeer snelle bewerking, vergelijkbaar met ls filename (maar recursief als filename een directory is).

In contrast,

find | grep filename 

zou find toestaan om een lijst met alle namen te genereren van de huidige directory en lager, die grep dan zou filteren. Dit zou duidelijk een veel langzamere operatie zijn.

Ik neem aan dat wat eigenlijk was bedoeld was

find . -type f -name "filename" 

Dit zou zoeken naar filename als de naam van een normaal bestand ergens in de huidige directory of lager.

Dit zal net zo snel (of vergelijkbaar snel) zijn als find | grep filename, maar de grep oplossing zou filename matchen met het volledige pad van elke gevonden naam, vergelijkbaar met wat -path "*filename*" zou doen met find.


De verwarring komt voort uit een misverstand over hoe find werkt.

Het hulpprogramma gebruikt een aantal paden en retourneert alle namen onder deze paden.

Je mag dan beperk de geretourneerde namen met behulp van verschillende tests die kunnen werken op de bestandsnaam, het pad, het tijdstempel, de bestandsgrootte, het bestandstype, enz.

Als je zegt

find a b c 

je vraagt find om elke naam te vermelden die beschikbaar is onder de drie paden a, b en c. Als dit namen zijn van reguliere bestanden in de huidige directory, dan worden deze geretourneerd. Als een van deze de naam van een directory is, wordt deze teruggestuurd samen met alle andere namen in die directory.

Wanneer ik dat doe

find . -type f -name "filename" 

Dit genereert een lijst met alle namen in de huidige directory (.) en lager. Vervolgens beperkt het de namen tot die van gewone bestanden, d.w.z. geen mappen enz., Met -type f. Dan is er nog een beperking voor namen die overeenkomen met filename met -name "filename". De tekenreeks filename kan een globbing-patroon voor bestandsnamen zijn, zoals *.txt (vergeet niet om het te citeren!).

Voorbeeld:

Het volgende lijkt het bestand met de naam .profile in mijn homedirectory “te vinden”:

$ pwd /home/kk $ find .profile .profile 

Maar in feite retourneert het alleen alle namen op het pad .profile (er is maar één naam, en dat is van dit bestand).

Vervolgens cd een niveau hoger en probeer het opnieuw:

$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory 

De find commando kan nu geen pad vinden met de naam .profile.

Als ik het echter naar de huidige map laat kijken en de teruggezonden namen beperk tot alleen .profile , vindt het vanaf daar ook:

$ pwd /home $ find . -name ".profile" ./kk/.profile 

Reacties

  • find filename zou alleen filename retourneren als filename niet van het type directory was (of van het type directory, maar had zelf geen vermelding)

Antwoord

Niet-technische uitleg: Jack zoeken in een menigte is sneller dan iedereen in een menigte zoeken en alles buiten beschouwing laten, behalve Jack.

Opmerkingen

  • Het probleem is dat het OP verwacht dat Jack wees de enige persoon in de menigte. Als dat het geval is, hebben ze ‘ geluk. find jack zal jack weergeven als het ‘ een bestand is met de naam jack, of alle namen in de directory als deze ‘ een directory is. Het ‘ is een misverstand over hoe find werkt.

Antwoord

Ik heb het probleem nog niet begrepen, maar kan wat meer inzichten geven.

Net als voor Kusalananda de find | grep oproep is duidelijk sneller op mijn systeem, wat niet veel logisch is. In eerste instantie ging ik uit van een soort bufferprobleem; dat schrijven naar de console de tijd tot de volgende syscall voor het lezen van de volgende bestandsnaam vertraagt. Het schrijven naar een pipe is erg snel: ongeveer 40MiB / s zelfs voor 32-byte schrijfbewerkingen (op mijn nogal trage systeem; 300 MiB / s voor een blokgrootte van 1MiB). Dus ging ik ervan uit dat find sneller uit het bestandssysteem kan lezen bij het schrijven naar een pipe (of bestand), zodat de twee bewerkingen voor het lezen van bestandspaden en het schrijven naar de console parallel kunnen draaien ( wat find als een enkel thread-proces niet op zichzelf kan doen.

Het is find “s fout

De twee aanroepen vergelijken

:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s 

en

:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s 

laat zien dat find iets ongelooflijk stoms doet (wat dat ook mag zijn). blijkt nogal incompetent te zijn in het uitvoeren van -name "*.txt".

Kan afhangen van de input / output-verhouding

Je zou kunnen denken dat find -name wint als er heel weinig te schrijven valt. Maar het wordt alleen maar gênanter voor find. Het verliest zelfs als er helemaal niets te schrijven is tegen 200K bestanden (13M pipe-gegevens) voor grep:

time find /usr -name lwevhewoivhol 

find kan zo snel zijn als grep, maar

Het blijkt dat find “s domheid met name zich niet uitstrekt tot andere tests. Gebruik in plaats daarvan een regex en het probleem is verdwenen:

:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s 

Ik denk dat dit als een bug kan worden beschouwd. Is er iemand die een bugrapport wil indienen? Mijn versie is find (GNU findutils) 4.6.0

Reacties

  • Hoe herhaalbaar zijn je timings? Als je eerst de -name -test hebt gedaan, dan kan het langzamer zijn geweest omdat de inhoud van de directory niet in de cache werd opgeslagen. (Bij het testen van -name en -regex vind ik dat ze ongeveer dezelfde tijd in beslag nemen, tenminste als er eenmaal rekening is gehouden met het cache-effect. Of het kan natuurlijk gewoon een andere versie zijn van find …)
  • @psmears Natuurlijk heb ik deze tests verschillende keren gedaan. Het cacheprobleem is al genoemd in de opmerkingen bij de vraag vóór het eerste antwoord. Mijn find versie is find (GNU findutils) 4.6.0
  • Waarom is het verrassend dat het toevoegen van -name '*.txt' langzamer gaat find? Het moet extra werk doen, elke bestandsnaam testen.
  • @Barmar Enerzijds kan dit extra werk extreem snel worden gedaan. Anderzijds scheelt dit extra werk ander werk. find hoeft minder gegevens te schrijven. En het schrijven naar een pipe is een veel langzamere bewerking.
  • Het schrijven naar een schijf is erg traag, het schrijven naar een pipe is niet zo erg, het kopieert alleen naar een kernelbuffer. Merk op dat het schrijven van meer naar /dev/null in uw eerste test op de een of andere manier minder systeemtijd heeft gebruikt.

Antwoord

Opmerking : ik neem aan dat je bedoelt find . -name filename (anders “zoek je naar verschillende dingen; find filename kijkt eigenlijk naar een pad met de naam bestandsnaam , dat bevat mogelijk bijna geen bestanden en wordt daarom erg snel afgesloten).


Stel dat u een directory heeft met vijfduizend bestanden. Op de meeste bestandssystemen worden deze bestanden feitelijk opgeslagen in een boom structuur , die het mogelijk maakt om snel een bepaald bestand te lokaliseren.

Dus als je find vraagt om een bestand te zoeken waarvan de naam alleen gecontroleerd hoeft te worden, zal find vragen aan voor dat bestand, en alleen dat bestand, naar het onderliggende bestandssysteem, dat zeer weinig paginas van de massaopslag zal lezen. Dus als het bestandssysteem zijn zout waard is, zal deze operatie veel sneller draaien dan de hele boom doorkruisen om alle items op te halen.

Als je om gewone find vraagt, maar dat is precies wat je doet, doorkruis je de hele boom en lees je. Elke. Enkele. Invoer. Met grote mappen, dit kan een probleem zijn (het is precies de reden waarom verschillende software, die veel bestanden op schijf moeten opslaan, “directory-trees” zullen creëren met twee of drie componenten diep: op deze manier hoeft elk blad slechts minder bestanden te bevatten) .

Antwoord

Laten we aannemen dat het bestand / john / paul / george / ringo / beatles bestaat en het bestand waarnaar je zoekt heet “stenen”

find / stones 

zoeken zal “beatles” vergelijken met “stenen” en laten vallen wanneer de “s” en “b” niet overeenkomen .

find / | grep stones 

In dit geval zal find “/ john / paul / george / ringo / beatles” doorgeven aan grep en grep wil Ik moet het hele pad doorlopen voordat ik kan bepalen of het een match is.

grep doet daarom veel meer werk en daarom duurt het langer

Opmerkingen

  • Heb je dat geprobeerd?
  • De kosten van de stringvergelijkingen (extreem eenvoudig en goedkoop) vallen volledig in het niet bij de IO (of gewoon syscall indien in cache) van de directory-lookups.
  • grep isn ‘ ta stringvergelijking, de vergelijking van reguliere expressies, wat betekent dat het zich een weg moet banen door de hele string totdat het ofwel vindt een wedstrijd of bereikt het einde. De zoekacties in de directory zijn altijd hetzelfde.
  • @Paranoid Hm, over welke versie van find heb je het? Het ‘ is blijkbaar niet zoiets als de find die ik ‘ m gebruikt in debian.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *