%20%C3%A9%20mais%20lento%20que%20getc()%3F%20.png)
Por que é read
mais lento que getc
?
Por exemplo, isto:
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;
}
é mais lento que isso:
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
usa a read
chamada do sistema, então por que é mais lento?
Responder1
Como getc() armazena em buffer os dados lidos antes de retorná-los, uma chamada para getc()
não resulta necessariamente em uma chamada para read()
. read()
é uma chamada de sistema, que leva muito mais tempo para ser realizada do que uma chamada de função normal porque o kernel tem mais operações para realizar. Quando você entra no espaço do kernel, ele muda sua pilha, salva todo o contexto, trata das interrupções para mascarar, e na outra ponta, quando terminar, restaura o contexto, as interrupções, coloca sua pilha de espaço de usuário de volta. É por isso que getc() é preferido porque economiza uma sobrecarga importante se você já tiver dados em buffer disponíveis.
Responder2
Tudo se resume ao fato de que as leituras de discos são orientadas a blocos: para ler um único byte de um disco, o hardware acaba lendo um bloco (512 ou 1024 ou algum número) de bytes, armazenando tudo isso em buffer, passando-o para o kernel . Se você ler o byte 0 do arquivo do bloco 0 do arquivo, fizer algum trabalho e depois ler o byte 1 do arquivo, o kernel provavelmente acabará lendo o bloco 0 do arquivo novamente. E novamente para o byte 2 e novamente para o byte 3. Sim, há cache potencial, tanto no kernel quanto na própria unidade de disco, mas o kernel lida com muitos processos, então talvez não.
Cada read()
chamada também precisa alterar a CPU do estado do usuário para o estado do kernel. Os mapeamentos de memória mudam, pelo menos. Provavelmente muitas outras coisas não tão óbvias acontecem. Isso também pode levar tempo.
Uma read()
chamada do sistema altera o estado da CPU e pode implicar E/S de disco. getc()
pode armazenar em buffer um bloco de disco inteiro (ou mais) no espaço do usuário, então talvez 512 chamadas getc()
façam com que o kernel leia um único bloco de disco, com uma única mudança de estado. Se você olhar, stdio.h
encontrará uma macro para uma constante BUFSIZ
que supostamente tem um tamanho eficiente (disco-bloco-múltiplo) para uma chamada read()
de write()
sistema para um arquivo no disco.