read
왜 보다 느린 가요 getc
?
예를 들면 다음과 같습니다.
for (;;) {
chr++;
amr=read(file1, &wc1, 1);
amr2=read(file2, &wc2, 1);
if (wc1 == wc2) {
if (wc1 == '\n')
line++;
if (amr == 0) {
if (eflg)
return (1);
return (0);
}
continue;
}
그보다 느립니다:
for (;;) {
chr++;
c1 = getc(file1);
c2 = getc(file2);
if (c1 == c2) {
if (c1 == '\n')
line++;
if (c1 == EOF) {
if (eflg)
return (1);
return (0);
}
continue;
}
getc
시스템 호출을 사용하면 read
왜 느린가요?
답변1
getc()
getc()는 읽기 데이터를 반환하기 전에 버퍼링하기 때문에 . 에 대한 호출은 커널에서 수행할 작업이 더 많기 때문에 일반 함수 호출보다 완료하는 데 시간이 더 오래 걸리는 시스템 호출 read()
입니다 . read()
커널 공간에 들어가면 스택을 변경하고, 모든 컨텍스트를 저장하고, 인터럽트를 마스크로 처리하고, 다른 한편으로는 완료되면 컨텍스트를 복원하고, 인터럽트하고, 사용자 공간 스택을 다시 넣습니다. 이것이 이미 사용 가능한 버퍼링된 데이터가 있는 경우 많은 오버헤드를 절약하기 때문에 getc()가 선호되는 이유입니다.
답변2
궁극적으로 디스크 읽기는 블록 지향적입니다. 디스크에서 단일 바이트를 읽으려면 하드웨어는 결국 바이트 블록(512, 1024 또는 일부 숫자)을 읽고 모든 바이트를 버퍼링한 다음 커널에 전달합니다. 파일의 블록 0에서 파일의 바이트 0을 읽고 일부 작업을 수행한 다음 파일에서 바이트 1을 읽으면 커널은 결국 파일의 블록 0을 다시 읽을 수 있습니다. 다시 바이트 2에 대해, 다시 바이트 3에 대해. 예, 커널과 디스크 드라이브 자체 모두에 잠재적인 캐시가 있지만 커널은 많은 프로세스를 처리하므로 아마도 그렇지 않을 것입니다.
각 read()
호출마다 CPU를 사용자 모드에서 커널 모드로 변경해야 합니다. 메모리 맵은 최소한 변경됩니다. 아마도 덜 분명한 다른 일들이 많이 있을 것입니다. 이것도 시간이 걸립니다.
시스템 read()
호출은 CPU 상태를 변경하며 디스크 I/O가 필요할 수 있습니다. getc()
전체 디스크 블록(또는 그 이상)이 사용자 공간에 버퍼링될 수 있으므로 512 호출로 getc()
인해 커널이 단일 디스크 블록을 읽고 단일 상태 변경을 수행할 수 있습니다. 살펴보면 디스크의 파일 또는 시스템 호출에 대한 유효(디스크 블록 다중) 크기가 stdio.h
되어야 하는 상수 매크로를 찾을 수 있습니다 .BUFSIZ
read()
write()