저는 쉘에서 GREP의 기능에 정말 놀랐습니다. 이전에는 Java에서 하위 문자열 메서드를 사용했지만 이제는 GREP를 사용하고 몇 초 만에 실행되며 제가 작성했던 Java 코드보다 엄청나게 빠릅니다. (내 경험에 따르면 나는 틀릴 수도 있습니다)
나는 그것이 어떻게 일어나고 있는지 알 수 없었다고 말하고 있습니까? 웹상에서도 많이 볼 수 없습니다.
누구든지 이것으로 나를 도울 수 있습니까?
저는 쉘에서 GREP의 기능에 정말 놀랐습니다. 이전에는 Java에서 하위 문자열 메서드를 사용했지만 이제는 GREP를 사용하고 몇 초 만에 실행되며 제가 작성했던 Java 코드보다 엄청나게 빠릅니다. (내 경험에 따르면 나는 틀릴 수도 있습니다)
나는 그것이 어떻게 일어나고 있는지 알 수 없었다고 말하고 있습니까? 웹상에서도 많이 볼 수 없습니다.
누구든지 이것으로 나를 도울 수 있습니까?
답변:
귀하의 질문이 GNU grep
구체적으로 관련되어 있다고 가정합니다 . 다음은 저자 Mike Haertel의 메모입니다.
GNU grep은 모든 입력 바이트를 보지 않기 때문에 빠릅니다.
그것은 각 바이트 거의 명령을 실행하기 때문에 GNU 그렙은 빠르게 수행 에 모습을.
GNU grep은 잘 알려진 Boyer-Moore 알고리즘을 사용합니다.이 알고리즘은 대상 문자열의 마지막 문자를 먼저 찾고, 일치하지 않는 문자를 찾을 때마다 입력에서 얼마나 빨리 건너 뛸 수 있는지 알려주기 위해 조회 테이블을 사용합니다.
GNU grep은 또한 Boyer-Moore의 내부 루프를 풀고, 풀린 모든 단계에서 루프 종료 테스트를 수행 할 필요가없는 방식으로 Boyer-Moore 델타 테이블 항목을 설정합니다. 그 결과 한도 내에서 GNU grep은 실제로 보는 각 입력 바이트에 대해 실행되는 x86 명령어가 평균 3 개 미만이며 많은 바이트를 완전히 건너 뜁니다.
GNU grep은 원시 Unix 입력 시스템 호출을 사용하고 데이터를 읽은 후 복사하는 것을 방지합니다. 또한 GNU grep은 입력을 줄로 끊는 것을 방지합니다. 줄 바꿈을 찾으려면 grep이 몇 배 정도 느려질 것입니다. 줄 바꿈을 찾으려면 모든 바이트를 살펴 봐야하기 때문입니다!
따라서 라인 지향 입력을 사용하는 대신 GNU grep은 원시 데이터를 큰 버퍼로 읽고 Boyer-Moore를 사용하여 버퍼를 검색하며 일치하는 항목을 찾은 경우에만 경계 줄 바꿈을 찾습니다 (다음과 같은 특정 명령 줄 옵션). n이 최적화를 비활성화합니다.)
이 답변은 여기 에서 가져온 정보의 하위 집합입니다 .
Steve의 탁월한 답변에 추가합니다.
널리 알려지지는 않았지만 , 긴 패턴에서 Boyer-Moore 는 더 나은 서브 선형 속도 를 달성하기 위해 더 긴 스트라이드에서 앞으로 건너 뛸 수 있기 때문에 짧은 패턴보다 긴 패턴 스트링 을 찾을 때 grep이 거의 항상 더 빠릅니다 .
예:
# 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
긴 형태는 35 % 더 빠릅니다!
어째서? Boyer-Moore 는 패턴 문자열에서 건너 뛰기 테이블을 구성하고 불일치가있을 때마다 입력의 단일 문자를 건너 뛰기 테이블의 문자와 비교하기 전에 가능한 가장 긴 건너 뛰기를 선택합니다 (마지막 문자에서 처음으로).
다음은 Boyer Moore를 설명하는 비디오입니다 (kommradHomer에 대한 크레딧).
(GNU 그렙에 대한) 또 다른 일반적인 오해는 즉 fgrep
보다 더 빨리이다 grep
. f
in fgrep
은 'fast'를 의미하지 않고 'fixed'를 의미하며 (man page 참조) 둘 다 동일한 프로그램이고 둘 다 Boyer-Moore를 사용하므로 fixed- 를 검색 할 때 속도 차이가 없습니다. 정규 표현식 특수 문자가없는 문자열. 내가 사용하는 유일한 이유 fgrep
는 정규 표현식 특수 문자 (예 .
: []
, 또는 *
) 가있을 때 그 자체로 해석되기를 원하지 않기 때문입니다. 그리고 심지어는 다음의 이식성 / 표준 양식은 grep -F
이상이 바람직하다 fgrep
.
xs.txt
에 100000000 'x'가 포함되어 있다고 가정 grep yx xs.txt
하면. 그러면 실제로 일치하는 항목을 찾는 것보다 빨리 찾지 못합니다 grep yxxxxxxxxxxxxxxxxxxx xs.txt
. Boyer-Moore-Horspool의 Boyer-Moore-Horspool 개선은이 경우 Skip-ahead에서 향상되지만 일반적인 경우에는 기계 명령이 세 개만있는 것은 아닙니다.
grep/fgrep/egrep
가 동일한 실행 파일에 대한 모든 하드 링크 였던 시절 은 지나간 것 같습니다. 그것들 (및 z*grep
bz*grep
즉석에서 압축을 푸는 유틸리티 와 같은 다른 확장 )은 이제 grep
. 단일 실행 파일과 쉘 래퍼 사이의 전환에 대한 흥미로운 역사적 코멘트는이 커밋에서 찾을 수 있습니다 : git.savannah.gnu.org/cgit/grep.git/commit/…