%20es%20m%C3%A1s%20lento%20que%20getc()%3F%20.png)
¿Por qué es read
más lento que getc
?
Por ejemplo, esto:
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;
}
es más lento que eso:
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 la read
llamada al sistema, entonces ¿por qué es más lento?
Respuesta1
Debido a que getc() almacena en buffer los datos leídos antes de devolverlos, una llamada a getc()
no necesariamente resulta en una llamada a read()
. read()
es una llamada al sistema, que lleva mucho más tiempo realizar que una llamada a función normal porque el kernel tiene más operaciones que hacer. Cuando ingresa al espacio del kernel, cambia su pila, guarda todo el contexto, se ocupa de las interrupciones para enmascarar y, en el otro extremo, cuando ha terminado, restaura el contexto, las interrupciones, vuelve a colocar la pila de su espacio de usuario. Es por eso que se prefiere getc() porque le ahorra una sobrecarga importante si ya tiene datos almacenados en el búfer disponibles.
Respuesta2
Todo se reduce al hecho de que las lecturas de los discos están orientadas a bloques: para leer un solo byte de un disco, el hardware termina leyendo un bloque (512 o 1024 o algún número) de bytes, almacenando todo eso en un buffer y pasándolo al kernel. . Si lee el byte 0 del archivo del bloque 0 del archivo, trabaja un poco y luego lee el byte 1 del archivo, el núcleo probablemente termine leyendo en el bloque 0 del archivo nuevamente. Y nuevamente para el byte 2, y nuevamente para el byte 3. Sí, existe un almacenamiento en caché potencial, tanto en el kernel como en la propia unidad de disco, pero el kernel maneja muchos procesos, así que tal vez no.
Cada read()
llamada también tiene que cambiar la CPU del estado de usuario al estado de kernel. Las asignaciones de memoria cambian, como mínimo. Probablemente sucedan muchas otras cosas no tan obvias. Eso también puede llevar tiempo.
Una read()
llamada al sistema cambia el estado de la CPU y podría implicar E/S de disco. getc()
puede almacenar en búfer un bloque de disco completo (o más) en el espacio del usuario, por lo que tal vez 512 llamadas getc()
hagan que el kernel lea en un solo bloque de disco, con un solo cambio de estado. Si observa, stdio.h
encontrará una macro para una constante BUFSIZ
que se supone que tiene un tamaño eficiente (bloque de disco múltiple) para una llamada read()
del write()
sistema a un archivo en el disco.