Grep nasıl bu kadar hızlı koşar?


113

GREP'in kabuktaki işlevselliğine gerçekten hayran kaldım, daha önce java'da alt dize yöntemini kullanıyordum ama şimdi bunun için GREP kullanıyorum ve saniyeler içinde çalışıyor, yazdığım java kodundan çok daha hızlı. (tecrübelerime göre yanılıyor olabilirim)

Nasıl olduğunu anlayamadım mı? web'de de pek bir şey yok.

Biri bana bu konuda yardım edebilir mi?


5
Açık kaynak olduğundan, kendiniz bir göz atabilirsiniz. gnu.org/software/grep/devel.html
driis

6
Ridiculous Fish, tam olarak sorunuzu yanıtlayan harika bir yazıya sahip: ridiculousfish.com/blog/posts/old-age-and-treachery.html
David Wolever

@WilliamPursell Yürütme süresi saniyeler içinde gittiğinde, JIT muhtemelen ısındı ve akıllara durgunluk veren fark, (1) grep'in ne yaptığı konusunda inanılmaz derecede akıllı olmasından ve (2) Java kodunun oldukça kötü bir algoritma seçimi yapmasından kaynaklanıyor grep'in odaklandığı spesifik sorun için.

3
Java uygulamanız JVM'yi başlatmak için ne kadar zaman harcıyor ve kodunuzu çalıştırmak için gerçekte ne kadar zaman harcıyor? Veya Java kodunuzda kullandığınız algoritmanın bir sorunu olabilir; O (N ^ 2) algoritmasının herhangi bir dilde yavaş olması muhtemeldir.
Keith Thompson

Yanıtlar:


169

Sorunuzun GNU grepözellikle ilgilendiğini varsayarsak . İşte yazar Mike Haertel'den bir not:

GNU grep hızlıdır çünkü HER GİRİŞ BYTE'E BAKMAKTAN KAÇINIR.

Buna o her bayt ÇOK BİRKAÇ yönergeleri çalıştırır çünkü GNU grep hızlı yapar bakmak.

GNU grep, ilk önce hedef dizginin son harfini arayan iyi bilinen Boyer-Moore algoritmasını kullanır ve eşleşmeyen bir karakter bulduğunda girdide ne kadar ileri atlayabileceğini söylemek için bir arama tablosu kullanır.

GNU grep ayrıca Boyer-Moore'un iç döngüsünü açar ve Boyer-Moore delta tablosu girişlerini, her açılmış adımda döngü çıkış testi yapmasına gerek kalmayacak şekilde ayarlar. Bunun sonucu, sınırda, GNU grep'in gerçekte baktığı her girdi baytı için çalıştırılan 3 x86 komut ortalamasından daha az olmasıdır (ve birçok baytı tamamen atlar).

GNU grep, ham Unix girdi sistemi çağrılarını kullanır ve verileri okuduktan sonra kopyalamaktan kaçınır. Dahası, GNU grep GİRİŞİ HATLARA KIRMAKTAN KAÇINIR. Yeni satırları aramak, grefti birkaç kat yavaşlatır, çünkü yeni satırları bulmak için her bayta bakması gerekir!

Dolayısıyla, satır yönelimli girdi kullanmak yerine, GNU grep ham verileri büyük bir arabelleğe okur, Boyer-Moore kullanarak arabelleği arar ve yalnızca bir eşleşme bulduğunda gider ve sınırlayıcı yeni satırları arar (Bazı komut satırı seçenekleri - n bu optimizasyonu devre dışı bırakın.)

Bu cevap, buradan alınan bilgilerin bir alt kümesidir .


41

Steve'in mükemmel cevabına eklemek için.

Yaygın olarak bilinmeyebilir, ancak grep kısa bir modelden daha uzun bir model dizisi için grep yaparken neredeyse her zaman daha hızlıdır , çünkü daha uzun bir modelde Boyer-Moore daha da iyi alt doğrusal hızlar elde etmek için daha uzun adımlarda ileri atlayabilir :

Misal:

# after running these twice to ensure apples-to-apples comparison
# (everything is in the buffer cache) 

$ time grep -c 'tg=f_c' 20140910.log
28
0.168u 0.068s 0:00.26

$ time grep -c ' /cc/merchant.json tg=f_c' 20140910.log
28
0.100u 0.056s 0:00.17

Daha uzun biçim% 35 daha hızlıdır!

Nasıl olur? Boyer-Moore , desen dizisinden bir ileri atlama tablosu oluşturur ve ne zaman bir uyumsuzluk varsa, girdideki tek bir karakteri atlama tablosundaki karakterle karşılaştırmadan önce mümkün olan en uzun atlamayı (son karakterden ilke) seçer.

İşte Boyer Moore'u açıklayan bir video (kommradHomer'a Kredi)

(GNU grep için) Başka bir ortak yanlış kanı olduğunu fgrepdaha hızlı olduğunu grep. fin fgrep'hızlı' anlamına gelmez, 'sabit' anlamına gelir (man sayfasına bakın) ve her ikisi de aynı program olduğundan ve her ikisi de Boyer-Moore kullandığından , sabit arama yaparken aralarında hız farkı yoktur. regexp özel karakterleri olmayan dizeler. Tek sebebi kullanım fgrepbir regexp özel karakter varken (gibidir ., []ya da *) bunun gibi yorumlanmamalıdır istemiyoruz. Ve o zaman bile daha taşınabilir / standart biçimi grep -Ftercih edilir fgrep.


3
Daha uzun kalıpların daha hızlı olması sezgiseldir. Desen bir bayt olsaydı, grep'in her baytı kontrol etmesi gerekirdi. Desen 4 bayt ise 4 baytlık atlama yapabilir. Kalıp metin kadar uzun olsaydı, grep yalnızca bir adım atardı.
noel

12
Evet, sezgiseldir - Boyer-Moore'un nasıl çalıştığını anlarsanız.
arielf

2
Aksi halde sezgiseldir. Samanlıkta uzun bir iğne bulmak daha kısa bir iğne bulmaktan daha kolay olurdu
RajatJ

2
"Daha uzun süre daha hızlı olma" nın karşı örneği, başarısız olmadan önce çok sayıda test yapmanız gereken ve yine de ilerleyemediğiniz durumlardır. Diyelim ki dosya xs.txt100000000 'x'ler içeriyorsa ve yaparsınız grep yx xs.txt, o zaman sizden daha erken bir eşleşme bulamaz grep yxxxxxxxxxxxxxxxxxxx xs.txt. Boyer-Moore'daki Boyer-Moore-Horspool iyileştirmesi, bu durumda ileri atlamayı geliştirir, ancak genel durumda muhtemelen sadece üç makine talimatı olmayacaktır.
2017

2
@Tino teşekkürler. Evet, görünen o ki (GNU) grep/fgrep/egrepaynı çalıştırılabilir dosyaya tüm sabit bağlantıların olduğu günler geride kaldı. Bunlar (ve z*grep bz*grepanında açılan araçlar gibi diğer uzantılar ) artık etrafta küçük kabuk sarmalayıcılardır grep. Tek bir yürütülebilir dosya ve kabuk sarmalayıcılar arasındaki geçişle
arielf
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.