[unix] grep은 어떻게 그렇게 빨리 실행됩니까?

저는 쉘에서 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. fin fgrep은 ‘fast’를 의미하지 않고 ‘fixed’를 의미하며 (man page 참조) 둘 다 동일한 프로그램이고 둘 다 Boyer-Moore를 사용하므로 fixed- 를 검색 할 때 속도 차이가 없습니다. 정규 표현식 특수 문자가없는 문자열. 내가 사용하는 유일한 이유 fgrep는 정규 표현식 특수 문자 (예 .: [], 또는 *) 가있을 때 그 자체로 해석되기를 원하지 않기 때문입니다. 그리고 심지어는 다음의 이식성 / 표준 양식은 grep -F이상이 바람직하다 fgrep.


답변