![터미널에서 멀티스레드 grep을 시작하는 방법은 무엇입니까?](https://linux55.com/image/63339/%ED%84%B0%EB%AF%B8%EB%84%90%EC%97%90%EC%84%9C%20%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C%20grep%EC%9D%84%20%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
250개가 넘는 파일이 포함된 폴더가 있는데 각 파일의 크기는 2GB입니다. 이 파일에서 문자열/패턴을 검색하고 결과를 파일로 출력해야 합니다 output
. 다음 명령을 실행할 수 있다는 것을 알고 있지만 너무 느립니다!
grep mypattern * > output
나는 일의 속도를 높이고 싶다. Java 프로그래머로서 저는 멀티스레딩을 사용하여 프로세스 속도를 높일 수 있다는 것을 알고 있습니다. grep
"멀티 스레드 모드"에서 시작하고 출력을 단일 파일에 쓰는 방법에 대해 고민하고 있습니다 output
.
답변1
두 가지 간단한 해결책이 있습니다. 기본적으로 xargs
또는 을 사용합니다 parallel
.
xargs 방법:
xargs
다음 과 같이 사용할 수 있습니다 find
.
find . -type f -print0 | xargs -0 -P number_of_processes grep mypattern > output
number_of_processes
여기서 시작할 최대 프로세스 수를 대체합니다 . 그러나 성능이 I/O 바인딩된 경우 상당한 성능을 보장할 수는 없습니다. 이 경우 I/O를 기다리는 동안 손실된 시간을 보상하기 위해 더 많은 프로세스를 시작하려고 할 수 있습니다.
또한 찾기를 포함하면 수정 시간 등과 같은 파일 모드보다 더 많은 고급 옵션을 지정할 수 있습니다.
Stéphane의 의견에 따르면 이 접근 방식의 한 가지 가능한 문제는 파일이 거의 없으면 xargs
해당 파일에 대해 충분한 프로세스를 시작하지 못할 수 있다는 것입니다. 한 가지 해결책은 -n
옵션을 사용하여 xargs
한 번에 파이프라인에서 가져와야 하는 매개변수 수를 지정하는 것입니다. 이 설정은 각 파일에 대해 새로운 프로세스를 -n1
강제로 xargs
시작합니다. 이는 파일이 매우 크고(이 질문의 경우) 파일 수가 상대적으로 적은 경우 바람직한 동작일 수 있습니다. 그러나 파일 자체가 작은 경우 새 프로세스를 시작하는 데 드는 오버헤드가 병렬성의 장점을 무너뜨릴 수 있으며, 이 경우 -n
큰 값이 더 좋습니다. 따라서 -n
이 옵션은 파일 크기와 개수에 따라 세부적으로 조정할 수 있습니다.
병렬 접근 방식:
또 다른 방법은 Ole Tange GNU Parallel 도구 parallel
(사용 가능) 를 사용하는 것입니다.여기). 이를 통해 병렬 처리를 보다 세밀하게 제어할 수 있으며 여러 호스트에 분산할 수도 있습니다(예를 들어 디렉터리를 공유하는 경우 유용합니다). 병렬성을 사용하는 가장 간단한 구문은 다음과 같습니다.
find . -type f | parallel -j+1 grep mypattern
이 옵션은 -j+1
머신의 코어 수를 초과하는 하나의 프로세스를 병렬로 시작하도록 지시하는 경우(이는 I/O 제한 작업에 유용하며 수를 늘려볼 수도 있습니다).
xargs
병렬성은 실제로 각 프로세스의 출력 순서를 보존하고 순차적인 출력을 생성한다는 장점도 있습니다. 예를 들어, xargs
프로세스 1이 한 줄을 생성하고 p1L1
, 프로세스 2가 한 줄을 생성하고 p2L1
, 프로세스 1이 또 다른 라인을 생성하는 경우 p1L2
출력은 다음과 같습니다.
p1L1
p2L1
p1L2
그리고 parallel
출력은 다음과 같아야 합니다.
p1L1
p1L2
p2L1
이는 종종 출력보다 더 유용합니다 xargs
.
답변2
grep CPU 속도를 높이는 방법에는 최소한 두 가지가 있습니다.
정규식 대신 고정 문자열을 검색하려면
-F
플래그를 지정하십시오.모드가 ASCII 전용인 경우 UTF-8 대신 8비트 로케일을 사용하십시오(예: )
LC_ALL=C grep ...
.
하드 드라이브에 병목 현상이 있는 경우에는 도움이 되지 않으며 병렬화도 도움이 되지 않습니다.
답변3
문제가 I/O 제한이 아닌 경우 멀티 코어 처리에 최적화된 도구를 사용할 수 있습니다.
sift(http://sift-tool.org, 면책조항: 저는 이 도구의 작성자입니다.) 또는 Silver Searcher(https://github.com/ggreer/the_silver_searcher).
스플릿 문자열 검색 대신 정규식 패턴을 사용하는 경우 실버 검색기의 파일 크기 제한은 2GB입니다.
답변4
나는 이것이 귀하의 질문에 완전히 대답하지 못하며 귀하에게 효과가 없을 수도 있다는 것을 알고 있습니다. 그러나 대중적인 유틸리티립그렙rg
기본적으로 병렬 처리를 사용하는 바이너리를 제공합니다 .
병렬성 정도를 제어하려는 경우 관련 플래그는 입니다 -j
. 매뉴얼 페이지에서:
-j, --스레드 수
사용할 대략적인 스레드 수입니다. 값이 0(기본값)이면 ripgrep이 휴리스틱을 사용하여 스레드 수를 선택합니다.
병렬성을 제쳐두고 ripgrep readme를 인용하면 rg
"이것은 유한 오토마타, SIMD 및 공격적인 리터럴 최적화를 사용하여 매우 빠른 검색을 수행하는 Rust의 정규 표현식 엔진 위에 구축되었습니다."
마지막으로, 상황에 따라 다음 기능 rg
중 grep
일부를 꺼야 할 수도 있습니다.
- 기본값은
rg
재귀적입니다.
폴더에 검색을 원하지 않는 하위 폴더가 포함된 경우 재귀 동작 비활성화를 사용할 수 있습니다 --max-depth 1
.
- 기본적으로
rg
.gitignore 또는 유사한 파일에 있는 파일은 검색되지 않으며 숨겨진 파일 및 바이너리도 검색되지 않습니다.
이러한 필터를 제거하려면 이 -u
플래그를 추가하면 됩니다(한 번은 파일 무시, 두 번은 파일 무시 및 숨기기, 세 번은 모든 필터 중지).
어쨌든 관심 있는 폴더에서 가장 간단한 경우(하위 디렉터리가 없고 기본 필터링이 실제로 해당 사례에 작동함) 다음을 실행할 수 있습니다.
rg mypattern > output
(폴더 외부에서 해당 경로를 추가해야 합니다.) rg mypattern myfolder > output
.
폴더에 하위 디렉터리가 있고 기본 필터링을 취소하려는 경우 명령은 다음과 같습니다.
rg --max-depth 1 -uuu mypattern > output
(그리고 폴더 외부에서 :) rg --max-depth 1 -uuu mypattern myfolder > output
.
이는 를 사용하지 않기 때문에 기술적으로 귀하의 질문에 대답하지 못하며 grep
귀하의 경우에 적용되지 않을 수 있습니다(예: 외부 유틸리티를 설치할 수 없거나 설치하고 싶지 않은 경우). 보다 rg
빠르지 grep
만 이것이 여전히 유용할 수 있다고 생각합니다.