%20langsamer%20als%20getc()%3F%20.png)
Warum ist read
langsamer als getc
?
Zum Beispiel dies:
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;
}
ist langsamer als das:
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
verwendet den read
Systemaufruf, warum ist es also langsamer?
Antwort1
Da getc() die gelesenen Daten puffert, bevor sie zurückgegeben werden, führt ein Aufruf von getc()
nicht unbedingt zu einem Aufruf von read()
. read()
ist ein Systemaufruf, der viel mehr Zeit in Anspruch nimmt als ein normaler Funktionsaufruf, da der Kernel mehr Vorgänge ausführen muss. Wenn Sie den Kernelspeicher betreten, ändert es Ihren Stapel, speichert den gesamten Kontext, behandelt die zu maskierenden Unterbrechungen und stellt am anderen Ende, wenn es fertig ist, den Kontext und die Unterbrechungen wieder her, legt Ihren Benutzerspeicherstapel zurück... Aus diesem Grund wird getc() bevorzugt, da es Ihnen einen erheblichen Mehraufwand erspart, wenn Sie bereits über verfügbare gepufferte Daten verfügen.
Antwort2
Es läuft darauf hinaus, dass das Lesen von Datenträgern blockorientiert erfolgt: Um ein einzelnes Byte von einem Datenträger zu lesen, liest die Hardware einen Block (512 oder 1024 oder eine andere Zahl) von Bytes, puffert alles und übergibt es an den Kernel. Wenn Sie Byte 0 der Datei aus Block 0 der Datei lesen, etwas Arbeit erledigen und dann Byte 1 aus der Datei lesen, liest der Kernel wahrscheinlich wieder Block 0 der Datei ein. Und noch einmal für Byte 2 und noch einmal für Byte 3. Ja, es gibt potenzielle Zwischenspeicherung, sowohl im Kernel als auch im Datenträger selbst, aber der Kernel verarbeitet viele Prozesse, also vielleicht nicht.
Jeder read()
Aufruf muss die CPU außerdem vom Benutzerzustand in den Kernelzustand ändern. Zumindest ändern sich die Speicherzuordnungen. Wahrscheinlich passieren noch viele andere, nicht so offensichtliche Dinge. Auch das kann einige Zeit dauern.
Ein read()
Systemaufruf ändert den CPU-Status und kann Festplatten-E/A nach sich ziehen. getc()
kann einen ganzen Festplattenblock (oder mehr) im Benutzerbereich puffern, sodass möglicherweise 512 Aufrufe dazu getc()
führen, dass der Kernel einen einzelnen Festplattenblock mit einer einzigen Statusänderung einliest. Wenn Sie nachsehen, stdio.h
finden Sie ein Makro für eine Konstante BUFSIZ
, die eine effiziente (ein Vielfaches eines Festplattenblocks) Größe für einen read()
oder einen write()
Systemaufruf einer Datei auf der Festplatte sein soll.