왜 화장실이 너무 느려?


17

왜 wc 유틸리티가 그렇게 느려 집니까?

큰 파일에서 실행할 때 md5sum보다 약 20 배 더 오래 걸립니다.

MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s

MyDesktop:/tmp$ time wc /tmp/bigfile 
         0          0 1073741824 /tmp/bigfile

real    0m45.969s
user    0m45.424s
sys     0m0.424s

MyDesktop:/tmp$ time md5sum /tmp/bigfile 
cd573cfaace07e7949bc0c46028904ff  /tmp/bigfile

real    0m2.520s
user    0m2.196s
sys     0m0.316s

파일이 null로 가득 차서 이상한 가장자리 조건이 아니라 파일이 임의의 데이터로 채워져 있거나 텍스트 파일 인 경우에도 동일한 성능 차이가 나타납니다.

(이것은 Ubuntu 13.04, 64 비트에 있습니다)


행 수에만 관심이있는 사용자를위한 참고 사항 : wc -l <filename>은 매우 큰 파일에서 훨씬 빠릅니다.
EL

답변:


27

그래서 나는 소스로 갔는데 속도가 2 바이트 문자를 처리하는 것처럼 보입니다. 기본적으로 읽은 모든 문자 mbrtowc()에 대해 넓은 문자로 변환하려고 호출해야합니다 . 그런 다음 넓은 문자를 테스트하여 단어 구분 기호, 줄 구분 기호 등인지 확인합니다.

실제로, 로케일 LANG변수를 기본값 en_US.UTF-8(UTF-8은 멀티 바이트 문자 세트)에서 변경하고 " C"(단순 싱글 바이트 문자 세트)로 설정 wc하면 싱글 바이트 최적화를 사용할 수있어 속도가 상당히 빨라집니다. 이전보다 약 1/4 만 소요됩니다.

또한 단어 ( -w), 줄 길이 ( -L) 또는 문자 ( -m)를 수행하는 경우 각 문자 만 확인하면됩니다 . 바이트 및 / 또는 행 수만 수행하는 경우 넓은 문자 처리를 건너 뛰고보다 빠르게 실행됩니다 md5sum.

나는 그것을 통해 실행 gprof하고 멀티 바이트 문자 (처리하는 데 사용되는 기능 mymbsinit(), mymbrtowc(), myiswprint(), 등) 버퍼를 통해 단계는 훨씬 더 복잡 그것을하기 때문이다 (30) 만 실행 시간 %, 및 코드에 대해 차지하는 가변 크기 문자에 대한 버퍼를 통해 가변 크기 단계를 처리하고 버퍼를 버퍼의 시작 부분으로 다시 확장하여 부분적으로 완성 된 문자를 채워서 다음에 처리 할 수 ​​있습니다.

이제 무엇을 찾아야하는지 알았으므로 일부 유틸리티에서 utf-8 속도 저하에 대해 언급 한 몇 가지 게시물을 발견했습니다.

/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/blogs/brendan/2011/12/08 / 2000x 성능 상 /


2
오, 방금 당신이 OP라는 것을 깨달았습니다. : p
Ivan Chau

2
이것이 가장 반항적 인 대답이지만 관련이 없습니다. md5sum절대 단어 수를 wc계산할 수 없으며 파일의 md5 해시를 계산하지 않습니다! 텍스트를 작성할 때 타자기와 비교할 때 왜 내 차가 그렇게 느린 지 묻는 것과 같습니다.
user49468

5
@ user49468 : 입력 파일의 각 바이트를 모두 읽어야하므로 둘 다 IO 바인딩 된 것으로 가정하는 것이 합리적입니다. 이 답변은 wc멀티 바이트 문자를 처리 할 때 실제로 CPU에 바인딩되어 있음을 증명합니다 .
MSalters

2
@ user49468 : wc와 md5sum은 다른 일을 할 수 있지만 파일을 읽고 상대적으로 간단한 계산을 수행합니다. 체크섬을 계산하고 바이트 수, 단어 구분 기호 및 줄 바꿈을 계산합니다. 글쎄, 나는 그것이 단순 하다고 생각 했지만 멀티 바이트 문자 세트의 추가 복잡성을 고려하지 않았습니다. "왜 내 미니 밴보다 내 차가 20 배 더 빨리 가게됩니까?" 두 가지 차이는 있지만 20 배 차이는 없을 것으로 예상합니다.
Johnny

1
@Johnny you car / minivan 비교는 둘 다 상점으로 운송하도록 설계된 측면이 부족합니다. 따라서 속도 비교가 이루어집니다. 자동차를 스트라이프 페인팅 차량과 비교하는 것이 더 적합합니다. 둘 다 거리를 사용하기 때문에 줄무늬 화가는 쇼핑을하거나 그 반대로도 적합하지 않기 때문에 속도가 관련이 없습니다.
user49468

1

그냥 추측하지만 당신 wc은하고있는 일과하는 일과 관련하여 사과를 오렌지와 비교하는 것 입니다 md5sum.

md5sum의 작업

md5sum파일을 처리 할 때 단순히 파일을 스트림으로 열고 메모리가 거의 필요하지 않은 MD5 체크섬 기능 을 통해 스트림을 실행하기 시작 합니다. 본질적으로 CPU 및 디스크 I / O 바운드입니다.

화장실 업무

wc실행될 때 파일을 한 번에 한 문자 씩 파싱하기 만하면됩니다. 실제로 파일의 구조를 분석하여 한 번에 한 줄씩 문자 사이의 경계와 단어 경계인지 여부를 결정해야합니다.

다음 문자열과 각 알고리즘을 구문 분석 할 때 각 알고리즘이 어떻게 이동해야하는지 생각해보십시오.

“Hello! Greg”
“Hello!Greg”
“Hello\nGreg”
“A.D.D.”
“Wow, how great!”
“wow     \n\n\n    great”
“it was a man-eating shark.”

MD5의 경우이 문자열을 한 번에 한 문자 씩 사소하게 이동합니다. 왜냐하면 wc그것은 단어와 줄 경계를 결정하고 그것이 나타나는 발생 횟수를 추적해야합니다.

추가 화장실 토론

.NET에서의 구현 에 대해 논의하는 2006 년 부터이 코딩 과제를 발견 했습니다wc . 의사 코드 중 일부를 살펴보면 어려움이 분명 wc하므로 다른 작업보다 속도가 너무 느린 이유를 밝히는 데 도움이 될 수 있습니다 .


1
표준 Unix wc 명령 과 다른 것을 설명하고 있습니다 (적어도 Ubuntu와 함께 제공되는 명령은 아님). 그 화장실은 고유 한 단어를 세지 않고 단어 만 세므로 "hello hello world"는 2가 아닌 3 개의 단어입니다.
Johnny

이 이론에 따르면, 라인 수 계산과 같은 간단한 작업이 더 빨리 진행되는 것처럼 들립니다. 줄 수를 지정하기 위해 'wc'를 변경하면 결과가 크게 수정됩니까? '화장실 -l'
여호수아 밀러

@Johnny-나는 당신이 그렇게 말한 독특한 단어를 포함한다고 말한 적이 없습니다. wc파일을 구문 분석 할 때 여러 항목을 계산합니다. 파일을 구문 분석 할 때 단어, 줄 및 바이트 수를 계산합니다. 매뉴얼 페이지를 읽으십시오!
slm

@JoshuaMiller-줄만 wc계산 한다고 말하면 내부 구문 분석이 제한되어서 모든 것을 계산하더라도 이러한 항목 만 계산하거나 줄 결과 만보고 하도록 명확하지 않습니다.
slm

@slm 당신은 독특한 단어를 계산한다고 말했고, 당신의 예는 “Hello! Greg”는 Hello 1, Greg 1 , 즉 각 단어의 수를 계산합니다. 그리고 당신이 연결 한 .Net 프로젝트는 "주된 작업 중 하나는 일련의 데이터를 통해 주어진 단어의 반복 횟수를 세는 것입니다. 예를 들어"Hello, yes hello "라는 문장이 있다면 Hello라는 단어가 두 번 사용되었고 yes라는 ​​단어가 한 번 사용되었습니다. " 실제로 에코 "Hello, yes hello" 의 결과 | wc --words 는 "Hello : 2, Yes : 1"이 아니라 "3"입니다.
Johnny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.