Neden egrep [wW] [oO] [rR] [dD] grep -i kelimesinden daha hızlı?


49

grep -iDaha sık kullanıyorum ve egrepeşdeğerinden daha yavaş olduğunu öğrendim, her harfin büyük veya küçük harfleriyle eşleşiyorum:

$ time grep -iq "thats" testfile

real    0m0.041s
user    0m0.038s
sys     0m0.003s
$ time egrep -q "[tT][hH][aA][tT][sS]" testfile

real    0m0.010s
user    0m0.003s
sys     0m0.006s

Yapmayan grep -iek testler egrepyapıyor mu?


12
grepDiğer yolunu deneyin, uçağın disk önbelleğe alınması arasındaki farkı ölçmemek için.
EightBitTony

3
Testten önce dosyayı elimden aldım, bu yüzden önbelleğe alındı. Ters sırayla yapılırsa neredeyse aynı zamanlar.
tildearrow

21
Bu, yerel ayara bağlı olabilir: bazı yerel ayarlar, büyük / küçük harf duyarlılığını hesaba katan karmaşık hesaplamaları içerir. GNU grep, Unicode içeren birçok durumda özellikle yavaştır. Hangi yerel ayarları kullandınız? Hangi Unix çeşidi altında? Test dosyanızın içeriği nedir?
Gilles 'SO- kötülükten

6
@Gilles iyi görünüyor, burada her testi 100 kez tekrar ediyorum (her şeyi zamanlıyor), belirlediğimden egrepdaha hızlı ve sonra ikisi de kabaca aynı. grepLANG=C
EightBitTony

2
@EightBitTony Saate bakın user(bu disk beklemeyi içermez). Farkında bir büyüklük sırası var.
kasperd

Yanıtlar:


70

grep -i 'a'grep '[Aa]'yalnızca ASCII yerel ayarlarında eşittir . Bir Unicode yerel ayarında, karakter eşdeğerleri ve dönüşümler karmaşık grepolabilir , bu nedenle hangi karakterlerin eşdeğer olduğunu belirlemek için fazladan çalışma yapmanız gerekebilir. İlgili yerel ayar, LC_CTYPEbaytların karakter olarak nasıl yorumlandığını belirleyen ayardır .

Tecrübelerime göre, grepbir UTF-8 yerel ayarında çağrıldığında GNU yavaş olabilir. Yalnızca ASCII karakterleri aradığınızı biliyorsanız, yalnızca ASCII yerel ayarlarında çağırmak daha hızlı olabilir. Bekliyorum

time LC_ALL=C grep -iq "thats" testfile
time LC_ALL=C egrep -q "[tT][hH][aA][tT][sS]" testfile

ayırt edilemez zamanlamalar üretecekti.

Olduğu söyleniyor, grepbulgunuzu Debian jessie'deki GNU ile çoğaltamıyorum (ancak test dosyanızı belirtmediniz). Bir ASCII yerel ayarı ( LC_ALL=C) ayarlarsam grep -i, daha hızlı olur. Etkileri, dizenin kesin yapısına bağlı olarak değişebilir; örneğin, tekrarlanan karakterlere sahip bir dize, performansı ( beklenen ) düşürür .


Yazar grep 2.10 ile birlikte gelen Ubuntu 14.04'ü kullanıyor. Harf duyarsız maçları (hız -ibaytlı yerel ayarlar ile) iyileşme olması gerekirdi 2,17 .
Lekensteyn

@Lekensteyn Bilmek güzel, teşekkürler. Ubuntu 14.04 gerçekte 2.16 grepiyle geliyor, ama bu da 2.17 öncesi; Grep 2.20 ile test ettim, bu neden aynı yavaşlamayı görmediğimi açıklıyor.
Gilles 'SO- kötülükten

Doğru, yanlış LTS sürümüne bakıyordum, Ubuntu 12.04 grep 2.10 ile gelirken Ubuntu 14.04 grep 2.16 içerir.
Lekensteyn

1
Herhangi bir yerel ayarda buna grep -i 'a'eşdeğer olduğundan eminim grep '[Aa]'. Uygun bir örnek grep -i 'i', ya olduğu grep '[Ii]'ya da grep '[İi]'(yukarıda nokta ile Büyük harf I, U + 130, Türk yerel). Ancak, grepbir yerel ayar verilen bu denklik sınıfını bulmak için etkili bir yol yoktur .
MSalters

15

Merakım dışında bunu bir Arch Linux sisteminde test ettim:

$ uname -r
4.4.5-1-ARCH
$ df -h .
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  720K  3.9G   1% /tmp
$ dd if=/dev/urandom bs=1M count=1K | base64 > foo
$ df -h .                                         
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  1.4G  2.6G  35% /tmp
$ for i in {1..100}; do /usr/bin/time -f '%e' -ao grep.log grep -iq foobar foo; done
$ for i in {1..100}; do /usr/bin/time -f '%e' -ao egrep.log egrep -q '[fF][oO][oO][bB][aA][rR]' foo; done

$ grep --version
grep (GNU grep) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

Ve sonra bazı istatistikler nezaket bir tek bir komutta bir sayı listesinin min, max, ortanca ve ortalama elde etmek için bir yolu var mı? :

$ R -q -e "x <- read.csv('grep.log', header = F); summary(x); sd(x[ , 1])"
> x <- read.csv('grep.log', header = F); summary(x); sd(x[ , 1])
       V1       
 Min.   :1.330  
 1st Qu.:1.347  
 Median :1.360  
 Mean   :1.362  
 3rd Qu.:1.370  
 Max.   :1.440  
[1] 0.02322725
> 
> 
$ R -q -e "x <- read.csv('egrep.log', header = F); summary(x); sd(x[ , 1])"
> x <- read.csv('egrep.log', header = F); summary(x); sd(x[ , 1])
       V1       
 Min.   :1.330  
 1st Qu.:1.340  
 Median :1.360  
 Mean   :1.365  
 3rd Qu.:1.380  
 Max.   :1.430  
[1] 0.02320288
> 
> 

Ben çıkıyorum en_GB.utf8yerel ayar, ama zaman neredeyse ayırt edilemez.

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.