Почему этот фильтр grep работает медленно? - PullRequest
6 голосов
/ 23 марта 2011

Я хочу получить первые две буквы в каждом слове в списке диктовых слов BSD, исключая те слова, которые начинаются только с одной буквы.

Без исключения из одной буквы он работает очень быстро:

time cat /usr/share/dict/web2 | cut -c 1-2 | tr '[a-z]' '[A-Z]' | uniq -c > /dev/null

real    0m0.227s
user    0m0.375s
sys 0m0.021s

Поиск '1006 *', однако, мучительно медленен:

time cat /usr/share/dict/web2 | cut -c 1-2 | grep '..' | tr '[a-z]' '[A-Z]' | uniq -c > /dev/null

real    1m16.319s
user    1m0.694s
sys 0m10.225s

Что здесь происходит?

Ответы [ 4 ]

9 голосов
/ 23 марта 2011

Проблема в языковом стандарте UTF-8, простое решение для ускорения 100x


Что действительно медленно на Mac, так это в языковом стандарте UTF-8.

Замените grep .. наLC_ALL=C grep .. тогда ваша команда будет выполняться в 100 раз быстрее.

Это, вероятно, верно и для Linux, за исключением того, что данный дистрибутив Linux, скорее всего, будет по умолчанию работать в среде C.

2 голосов
/ 23 марта 2011

Я не знаю, почему это так ужасно. Но я знаю, что один быстрый способ ускорить его - инвертировать ваше выражение grep(1) с помощью -v и выбросить все односимвольные строки:

$ time cat /usr/share/dict/words | cut -c 1-2 | grep -v '^.$' | tr '[a-z]' '[A-Z]' | uniq -c > /dev/null

real    0m0.086s
user    0m0.090s
sys  0m0.000s
1 голос
/ 23 марта 2011

это может быть даже быстрее, если вы сократите использование лишних труб и бесполезной кошки

$ awk '{ a[toupper(substr($0,1,2))]++ } END{for(i in a) print i,a[i] }' file
1 голос
/ 23 марта 2011

Это может работать немного лучше, а также избавит вас от необходимости разрезать трубку.

cat /usr/share/dict/web2 | egrep -o '^.{2,}' | tr '[a-z]' '[A-Z]' | uniq -c > /dev/null
...