2009-09-01 6 views
20

랜덤 생성 된 입력 파일을 읽고 동일한 문자열을 반향 출력하는 동일한 프로그램을 제공 한 후. 유일한 차이점은 한 쪽에서는 리눅스 syscalls에서 읽기 및 쓰기 메소드를 제공하고 다른 쪽에서는 fread/fwrite를 사용하고 있다는 것입니다.왜 fwrite libc 함수가 syscall write 함수보다 빠릅니까?

크기가 10Mb 인 입력을 사용하여/dev/null에 출력하고 파일이 캐시되지 않았는지 확인하면서 매우 작은 버퍼를 사용할 때 libc의 fwrite가 큰 배율로 빠릅니다. (1 바이트의 경우).

real 0m0.948s 
user 0m0.780s 
sys  0m0.012s 

그리고 콜 쓰기 사용 :

real 0m8.607s 
user 0m0.972s 
sys  0m7.624s 

내가 생각할 수있는 유일한 가능성은 내부적으로 libc에 이미 내 버퍼링이다를 여기

는에 fwrite를 사용하여, 시간에서 내 출력 입력 ... 불행히도 웹상에서 많은 정보를 찾을 수 없으므로 여기의 전문가가 나를 도울 수 있습니다.

+4

"내부적으로 libc가 이미 내 입력을 버퍼링하고 있습니다". 이것이 바로 그것이하는 일입니다. 당신이 원한다면 아마 libc의 소스 코드를 읽을 수도 있고, 정확히 어떻게하고 있는지 볼 수 있습니다. – kquinn

답변

29

크기 10M 바이트의 입력으로 내 응용 프로그램 타이밍 및 을/dev/null로 반향 및 에 파일이 캐시되지 확인하고, I는 libc의의 frwite는 LARGE로 빠른 것으로 나타났습니다 매우 작은 버퍼 ( 경우 1 바이트)를 사용하여 을 스케일합니다.

fwrite은 버퍼링 된 스트림에서 작동합니다. 따라서 많은 작은 버퍼는 버퍼가 가득 찰 때까지 (또는 스트림을 플러시하거나 닫을 때까지) 값 비싼 시스템 호출을 실행하지 않기 때문에 더 빠릅니다. 반면에 작은 버퍼가 write으로 전송되면 각 버퍼에 대한 비용이 많이 드는 시스템 호출이 실행됩니다. 속도가 느려집니다. 1,024 바이트 스트림 버퍼를 사용하고 1 바이트 버퍼를 쓰면 write킬로바이트 당 1024 번이 아니라 fwrite 번으로 바뀌어 전화가 걸려 오는 것입니다. 차이점을 확인 하시겠습니까?

큰 버퍼의 경우 버퍼링이 적어서 fwritewrite 사이의 일관된 시스템 호출 수가 있기 때문에 차이가 작습니다.

즉, fwrite(3)은 출력을 청크로 수집 한 라이브러리 루틴이며 write(2)을 호출합니다. 이제 write(2)시스템 콜입니다. 은 커널에 트랩합니다. 이것이 I/O가 실제로 일어나는 곳입니다. 단순히 커널을 호출하는 데 약간의 오버 헤드가 있으며, 실제로 뭔가를 쓰는데 걸리는 시간이 있습니다. 큰 버퍼를 사용하면 결국 write(2)이 더 빠르다는 것을 알게 될 것입니다. fwrite 당 하나 이상의 시간을 쓰는 경우 fwrite 버퍼링 오버 헤드가 바로 그 것입니다. 더 많은 오버 헤드가 있습니다.

자세한 내용은 표준 I/O 스트림을 설명하는 this document을 참조하십시오.

14

write (2) 기본 커널 작업입니다.

fwrite (3)은 write (2) 위에 버퍼링을 추가하는 라이브러리 함수입니다.

커널 호출을 수행하기위한 오버 헤드 때문에 fwrite (3)은 작은 (예 : 한 줄에 하나씩) 바이트 수의 경우 더 빠릅니다.

큰 (블록 입출력) 바이트 수의 경우, write (2)은 버퍼링에 신경 쓰지 않기 때문에 더 빠르며 두 경우 모두 커널을 호출해야합니다.

소스를 cp (1)로 보면 버퍼링을 볼 수 없습니다.

마지막으로 고려해야 할 사항이 있습니다. ISO C v Posix. fwrite과 같은 버퍼 라이브러리 함수는 ISO C에 지정되어 있으며 write과 같은 커널 호출은 Posix입니다. 많은 시스템이 Posix 호환성을 요구하지만, 특히 정부 계약의 자격을 얻으려고 할 때 실제로는 유닉스 계열 시스템에만 해당됩니다. 따라서 버퍼링 된 작업이 더 휴대 가능합니다. 결과적으로 리눅스 cp은 확실히 write을 사용하지만 크로스 플랫폼에서 작동해야하는 C 프로그램은 fwrite를 사용해야 할 수도 있습니다.

+0

나는 최근에 인터뷰를했는데 차이점에 대한 동일한 추론을했습니다. 필자는 "이 차이에 대한 지식은 완전히 가짜입니다!"라고 대답했습니다. 면접관은 나에게 매우 오만한 것처럼 보였다. 그래도 glibc를 통한 호출과 커널에 직접 호출하는 호출간에 다른 차이점이 있는지 확인하고 싶었습니다. –

+0

@PK, 대답을 업데이트했습니다 ... – DigitalRoss