다음 명령은 결과를 출력하는 데 약 10분 정도 걸립니다.
find . -name "muc*_*_20160920_*.unl*" | xargs zcat |
awk -F "|" '{if($14=="20160920100643" && $22=="567094398953") print $0}'| head
성능을 어떻게 향상시킬 수 있나요?
답변1
그것은 이미 상당히 최적화되어 있습니다. 다음과 같은 자세한 내용을 알지 못하면 병목 현상이 무엇인지 알기가 어렵습니다.
- 스토리지 유형(HD, SSD, 네트워크, RAIDed)
- 일치하는 파일의 수와 평균 크기
- 디렉터리 및 기타 일치하지 않는 파일 수
- 각 줄의 필드 수
- 줄의 평균 길이
어떠한 경우에도 할 수 있는 일:
- 귀하의 / 지원하는 경우 또는
-print | xargs로 교체하십시오 . 잘못된 것일 뿐만 아니라 어떤 문자가 공백인지 알아내고 값비싼 인용 처리를 수행하기 위해 문자를 디코딩해야 하기 때문에 비용도 더 많이 듭니다.-exec cmd {} +-print0 | xargs -r0findxargs-print | xargsxargs - 로케일을 C(
export LC_ALL=C)로 수정합니다. 여기에 관련된 모든 문자(|및 파일 내용의 십진수, 라틴 문자, 파일 이름의 마침표 및 밑줄)는 이식 가능한 문자 세트의 일부이므로 문자 세트가 UTF-8 또는 다른 멀티 바이트 문자 세트인 경우 전환 단일 바이트 문자 세트를 사용하여 C로 변환하면find및 에 대한 많은 작업이 안전해집니다awk. awk부품을 다음과 같이 단순화합니다awk -F "|" '$14 == "20160920100643" && $22 == "567094398953"'.- 출력을 로 파이프하고 있으므로 출력 버퍼링을 비활성화 하여 해당 10개 라인을 가능한 한 빨리 출력할
head수 있습니다 . 또는 을awk사용하면 이를 사용할 수 있습니다 . 아니면 in 을 추가할 수도 있습니다 .gawkmawkfflush()if (++n == 10) exitawk
요약하자면:
(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -exec zcat {} + |
awk -F "|" '$14 == "20160920100643" && $22 == "567094398953" {
print; if (++n == 10) exit}')
CPU가 병목 현상을 일으키는 경우 멀티 코어 GNU 시스템에서 다음을 시도해 볼 수 있습니다.
(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -print0 |
xargs -r0P 4 -n 100 sh -c '
zcat "$@" |
awk -F "|" "\$14 == "20160920100643" && \$22 == "567094398953" {
print; fflush()}"' sh | head)
zcat | awk100개 파일 배치에서 4개 작업을 병렬로 실행합니다 .
그것이 20160920100643타임스탬프인 경우 그 이전에 마지막으로 수정된 파일을 제외할 수 있습니다. GNU 또는 BSD를 사용 find하면 -newermt '2016-09-20 10:06:42'.
라인에 필드 수가 많은 경우 awk이를 분할하고 너무 많은 $n필드를 할당하면 페널티가 발생합니다. 처음 22개 필드만 고려하는 접근 방식을 사용하면 작업 속도가 빨라질 수 있습니다.
grep -E '^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)'
명령 대신 awk. GNU를 사용하면 병렬 접근 방식에서 가능한 한 빨리 라인을 출력하거나 비병렬 접근 방식에서 10번 일치 후 중지하는 옵션을 grep추가합니다 .--line-buffered-m 10
요약하자면, CPU가 병목 현상이고 시스템에 CPU 코어가 4개 이상 있고 muc* 파일이 400개 이상 있고 GNU 시스템을 사용하는 경우(일반적으로 grepGNU보다 훨씬 빠릅니다 awk):
(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -newermt '2016-09-20 10:06:42' -print0 |
xargs -r0P 4 -n 100 sh -c '
zcat "$@" |
grep --line-buffered -E \
"^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)"
' sh | head)
병렬 접근 방식에서는 명령의 출력이 grep혼합될 수 있습니다(라인 버퍼링을 사용하고 제공된 라인의 크기가 몇 킬로바이트 미만이므로 라인 경계는 보존되어야 함).
답변2
@Stéphane Chazelas의 답변은 명령 파이프라인을 최적화하는 방법에 대한 많은 세부 정보를 제공합니다.
find . -name "muc*_*_20160920_*.unl*" | xargs zcat |
awk -F "|" '{if($14=="20160920100643" && $22=="567094398953") print $0}'| head
나는 실제로 가장 많은 시간을 보내는 곳을 측정하는 문제에 접근하는 또 다른 방법을 제공할 것입니다. 시간이 어디에 소비되는지 찾으면 그에 대해 무엇을 해야 할지 결정할 수 있습니다. 10분의 실행 시간을 향상시키려면 2초가 걸리는 단계를 최적화하는 것은 거의 쓸모가 없습니다.
명령 파이프라인을 보면 세 가지 사항이 주목을 받습니다.
find .- 디렉토리 구조는 어떤가요? 디렉터리당 파일 수는 몇 개입니까? 명령이 실행되는 시스템의 로컬 디렉터리입니까? 원격 파일 시스템은많은더 느리게.-name "muc*_*_20160920_*.unl*"- 디렉토리 구조에서 모든 파일 이름은 얼마나 가깝습니까? 그것들은 모두 이름에 "가깝고" 일치하기 어렵고/CPU 집약적입니까? 왜냐하면모든디렉터리 트리에 있는 파일의 이름은 디스크에서 읽어와 패턴과 비교되어야 합니다.xargs zcat- 특히 위의 문제와 그 자체xargs에 비해 성능 문제가 너무 클 것 같지는 않습니다 . 파일 이름이 10,000개 또는 심지어 10,000,000개라도 이름만 전달하고 구문 분석하는 데 사용되는 시간은 소요되는 시간에 비해 거의 확실히 미미합니다.findzcat발견이름을 확인한 다음 모든 파일 자체를 열고 압축을 풉니다. 파일의 크기는 얼마나 됩니까? 전체 압축을 풀기 때문에모든의 파일 이름 패턴과 일치하는 파일입니다find.
주요 성능 문제가 무엇인지 어떻게 확인할 수 있습니까? 파이프라인에서 각 명령의 성능을 측정합니다. (보다https://stackoverflow.com/questions/13294554/how-to-use-gnu-time-with-pipeline전체 파이프라인 타이밍에 대한 자세한 내용은 다음 명령을 실행하여 각 단계가 전체 파이프라인의 처리 시간에 기여하는 시간을 확인할 수 있습니다.
/usr/bin/time find .- 디렉터리 트리를 실행하는 데 걸리는 시간을 알려줍니다. 속도가 느리다면 더 나은 스토리지 시스템이 필요합니다. 파일 시스템 캐시 플러시최악의 측정을 얻기 위해 타이밍을 맞추기 전에 시간 측정을 find다시 실행하고 캐싱이 성능에 얼마나 영향을 미치는지 확인하십시오. 디렉터리가 로컬이 아닌 경우 파일이 있는 실제 시스템에서 명령을 실행해 보세요.
/usr/bin/time find . -name "muc*_*_20160920_*.unl*"- 파일 이름을 패턴 일치시키는 데 걸리는 시간을 알려줍니다. 다시 한번, 파일 시스템 캐시를 플러시하고 두 번 실행하십시오.
/usr/bin/time bash -c "find . -name 'muc*_*_20160920_*.unl*' | xargs zcat > /dev/null"- 이것이 파이프라인의 긴 실행 시간의 주요 구성 요소라고 생각됩니다. 이것이 문제인 경우 zcatStéphane Chazelas 답변에 따라 명령을 병렬화하는 것이 최선의 대답일 수 있습니다.
대부분의 시간을 보내는 위치를 찾을 때까지 원래 명령 파이프라인의 단계를 테스트 중인 명령 파이프라인에 계속 추가하세요. 다시 한 번, 나는 그것이 zcat단계라고 생각합니다. 그렇다면 zcat@Stéphane Chazelas가 게시한 병렬화가 도움이 될 것입니다.
병렬화는 zcat도움이 되지 않을 수도 있습니다.아프다성능이 저하되고 처리 속도가 느려집니다. 한 번에 하나만 zcat실행되면 IO는 디스크 탐색을 최소화하는 좋은 스트리밍 패턴을 가질 수 있습니다. 한 번에 여러 zcat프로세스가 실행되면 디스크 헤드가 검색해야 하고 미리 읽기가 덜 효과적이기 때문에 IO 작업이 경쟁하고 실제로 처리 속도가 느려질 수 있습니다.
해당 zcat단계가 주요 성능 병목 현상이고 zcat한 번에 여러 프로세스를 실행해도 도움이 되지 않거나 실제로 속도가 느려지는 경우 파이프라인은 IO에 바인딩되어 있으므로 더 빠른 스토리지를 사용하여 문제를 해결해야 합니다.
그리고 다시 - 디렉터리가 명령 파이프라인을 실행하는 컴퓨터의 로컬이 아닌 경우 파일 시스템이 실제로 있는 컴퓨터에서 실행해 보세요.
답변3
댓글에 언급된 대로zgrep이러한 종류의 작업에 더 나은 선택입니다.글로스타**다음과 같이 사용할 수 있는 옵션all path inside the directory except hidden
shopt -s globstar
zgrep -m 10 '^\([^|]*|\)\{13\}20160920100643|\([^|]*|\)\{7\}567094398953' ./**muc*_*_20160920_*.unl*
shopt -u globstar
답변4
지적한 대로 추가 세부정보 없이는 정답을 제공하는 것이 불가능합니다.
locate -0 -b -r '^muc.*_.*_20160920_.*.unl.*gz' |
xargs -0 zcat |
awk -F "|" '$14=="20160920100643" && $22=="567094398953"'| head
**1: 찾기(사용 가능한 경우)는 또는 보다 훨씬 빠릅니다find. 사용된 정규 표현식을 조정해야 합니다...2 및 3: PO의 필터
@rudimeier가 현명하게 지적했듯이 locate. (예: 대부분의 Linux 시스템에서 찾기는 매일 업데이트됩니다. 이렇게 하면 오늘 생성된 파일을 찾을 수 없습니다.)
그럼에도 불구하고 찾기가 가능하다면 이는 매우 인상적인 속도 향상을 가져올 것입니다.
time ...PO가 다양한 솔루션을 제공할 수 있다면 흥미로울 것입니다.


