2013-12-13 9 views
5

Im Folgenden sind die Erklärungen von read und pread:Zwischen read() und pread(), welcher Weg ist effizienter?

#include <unistd.h> 
ssize_t read(int fd, void *buf, size_t count); 
ssize_t pread(int fd, void *buf, size_t count, off_t offset); 

Wir alle wissen, dass sie fast die gleiche Funktionalität haben, aber welche ist effizienter? Geben Sie die Anwendungsfälle ein: 1.Scannen Sie eine große Datei. 2.Random eine große Datei lesen.

+0

es erscheint zweimal lesen, anstatt pread proto – ShinTakezou

+3

Nun, eine Funktion versucht, einen bestimmten Offset vor dem Lesen, während der andere nicht. Sie müssen also entscheiden, ob Sie z. 'lseek' gefolgt von' read' ist besser oder nicht, als nur 'pread' zu verwenden. Eine Möglichkeit, sich zu entscheiden, ist * Benchmark * für Ihren speziellen Anwendungsfall. In der Tat würde ich sagen, es ist der einzige Weg zu entscheiden, und diese Frage ist nicht zu beantworten, weil wir Ihren Anwendungsfall nicht kennen. –

+4

Wirklich, du sorgst dich darum? Der Unterschied ist, wenn es welche gibt, vielleicht 5-6 Taktzyklen. Ein Festplattenzugriff ist _25-30 Millionen_ Taktzyklen ... – Damon

Antwort

6

Hängt davon ab, wie Sie "effizient" definieren. Wenn Sie nach Leistung fragen, ist der Unterschied mikroskopisch. Verwenden Sie also den, der das Problem für Sie löst. In vielen Fällen ist pread die einzige Option, wenn es sich um Threads handelt, die aus einer Datenbank oder einer anderen Datenbank lesen. In anderen Fällen ist read die einzig sinnvolle Option. Und die Frage ist ein bisschen unfair, da pread mehr als read tut. Ein fairer Vergleich wäre lseek + read, die definitiv langsamer als nur pread sein wird.

Lassen Sie uns die Unterschiede in der Implementierung von beiden in einer Betriebssystemquelle betrachten, die ich zur Verfügung hatte. Ich schneide den exakt gleichen Code aus beiden Funktionen heraus, um die Unterschiede hervorzuheben. Es gibt viel mehr Code als das.

Dies ist Teil pread:

vp = (struct vnode *)fp->f_data; 
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO || 
     (vp->v_flag & VISTTY)) { 
    return (ESPIPE); 
} 

offset = SCARG(uap, offset); 
if (offset < 0 && vp->v_type != VCHR) 
    return (EINVAL); 

return (dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval)); 

Dies entspricht Teil read:

return (dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval)); 

So hat pread einige zusätzliche Kontrollen, um sicherzustellen, dass wir versuchen, nicht zu versuchen, auf einer Pipe, Fifo, Tty usw. Und es überprüft, dass wir nicht einen negativen Offset von einem Zeichengerät lesen. Es aktualisiert auch nicht den Offset im Dateizeiger (fp im Code).

2

Es ist auf den Betrieb ab, die Sie mit read() und pread()

Zum Beispiel tun werden: Wenn Sie eine Datei lesen und Sie rufen read() zweimal, wird read() automatisch den Zeiger vorzurücken. Aber pread() bleibt auf dem gleichen Offset.

0

Es ist nicht wirklich eine Frage der Effizienz, sondern der Funktionalität.

Wenn ich eine Datei von Position x und weiter lesen möchte, würde ich lseek (falls erforderlich) verwenden, gefolgt von so vielen read, wie ich brauchte.

Wenn ich von zufälligen Stellen in der Datei lesen und viel hin und her springen möchte, würde ich pread statt lseek + read verwenden.

Man würde erwarten, dass pread etwas weniger effizient ist als read, aber etwas effizienter als lseek + read. Der Unterschied ist wahrscheinlich nicht größer als ein paar Taktzyklen.

+0

Und wie @ Janneb in anderen Antworten darauf hingewiesen hat, bevorzugen Sie 'pread', wenn die Datei zwischen Threads geteilt wird und die Lesevorgänge unserialisiert sind. – rodrigo

0

Der Hauptvorteil von pread besteht darin, dass Sie in einem Multithread-Programm keine E/A serialisieren müssen, um zu verhindern, dass ein anderer Thread den Dateioffset ändert.

Ansonsten ist der Unterschied wahrscheinlich im Rauschen (aber messen Sie es für Ihren Anwendungsfall, wenn Sie wirklich interessiert sind!). Da Ihre Frage mit "linux", IIRC im Linux-Kernel markiert ist, hat die I/O-Lesefunktion der unteren Ebene eine Pread-ähnliche Schnittstelle. Für den read() - Syscall sucht er den Offset aus der Dateitabelle und ruft dann die untere Lesefunktion mit diesem Offset auf, während der pread() - Syscall den vom Aufrufer bereitgestellten Offset verwendet. Ich würde also annehmen, dass pread() etwas effizienter ist als lseek() + read() (ein Syscall weniger ist der Hauptvorteil), aber wahrscheinlich nichts, worüber man sich Sorgen machen müsste, da syscalls unter Linux relativ schnell sind.

Verwandte Themen