Ich versuche zu verstehen, wie Named Pipes funktionieren, damit ich meine One-Way-Interprozesskommunikation rationalisieren kann. Ich erwarte einen gewissen Overhead durch das Kopieren von Daten in einen Ringpuffer, von dem ich angenommen hätte, dass er im RAM gespeichert ist, und daher erwarte ich, dass die Pipe viel schneller ist als das Schreiben in eine Datei (weil der RAM um Größenordnungen schneller ist als die Festplatte).
Stattdessen stellte ich fest, dass die Named Pipe (oder anonyme Pipe) ungefähr die gleiche Geschwindigkeit wie eine Datei hat. Dies ist auf einem 3-GHz-Desktop mit einem normalen Festplattenlaufwerk (nicht Solid State) unter Ubuntu Linux. Hier ist ein vereinfachtes Testprogramm in Python:
import sys
import time
import random
megabyte = "".join(random.choice("abcdefghijklmnopqrstuvwxyz") for x in range(1024**2))
while True:
before = time.time()
sys.stdout.write(megabyte)
after = time.time()
sys.stderr.write("{} microseconds\n".format(1e6 * (after - before)))
Rohrleitungen direkt zu /dev/null
:
python test.py > /dev/null
ergibt 2,1 Mikrosekunden (konstant) pro Megabyte.
Zu einer Datei leiten:
python test.py > /tmp/testout.txt
Sprünge zwischen 500 Mikrosekunden und 930 Mikrosekunden (der größere Wert wird häufiger, wenn die Datei größer wird - vermutlich wird Speicherplatz benötigt).
Dann die Named Pipe:
mkfifo testpipe
cat testpipe > /dev/null &
python test.py > testpipe
ergibt 640 Mikrosekunden (Konstante) und eine unbenannte Pipe:
python test.py | cat > /dev/null
ergibt ebenfalls 650 Mikrosekunden (konstant).
Kann jemand erklären, warum die Geschwindigkeit der Pipe eher der Geschwindigkeit der Datei als der Geschwindigkeit der Pipe entspricht /dev/null
? Könnte es sein, dass ich irgendwo einen Schalter habe, der sagt: "Führe Pipes durch einen dateibasierten Puffer und nicht durch einen RAM-basierten Puffer", und kann ich diesen Schalter ändern? Könnte es eine Kernel-Option oder eine Shell-Variable sein?
Eine andere Interpretation: Nehmen wir an, dass die Festplattenausgabe zwischen 500 und 930 Mikrosekunden springt, weil der 500 nur Piping-Vorgänge ausführt und der 930 tatsächlich schreibt. Dann sind die 500 ~ 640 für die Verrohrung in beiden Fällen äquivalent. Warum gibt es bei dieser Interpretation nur einen Faktor zwei zwischen Piping und tatsächlichem Schreiben auf die Festplatte? Websites, die sich mit RAM-Festplatten befassen, geben an, dass RAM-Festplatten 50 bis 200 Mal schneller sind als Festplatten.
/dev/null
ist eigentlich recht billig, während das Schreiben an einer anderen Stelle - sei es eine Datei, ein FIFO, eine Pipe oder was auch immer - viel teurer ist, da es "viel" Handhabungsaufwand erfordert.Antworten:
Sie sehen keinen Leistungsvorteil, weil Sie beim Verwenden einer Datei nicht auf die Festplatte treffen - die Daten werden auf die Festplatte übertragen, aber Ihr Ausführungsthread muss nicht darauf warten, dass sie dort landen nicht wirklich zu sehen , die Geschwindigkeit Strafe von der Scheibe zu treffen.
Wenn Sie warten möchten, bis der Festplattenvorgang abgeschlossen ist, um zu sehen, wie viel langsamer das wird, rufen Sie a
sync()
(wie es bei Ihrer Python-Version variiert, finden Sie hier ) an - Sie werden Zehntausende von Mikrosekunden nur für Ihre Festplatte benötigen Suchen Sie ein paar Mal, um die Datei ausschreiben zu lassen (vorausgesetzt, sie verfügt nicht über einen schnellen Schreibcache wie in einem RAID-Controller).quelle
sync()
beträgt die Schreibzeit auf der Festplatte durchschnittlich 74.000 Mikrosekunden. (Das habeflush()
ich in einer Variante meines Tests nicht gemacht.) Also ist meine Interpretation, dass die 500 ~ 640 Mikrosekunden pro Megabyte wirklich der Pipe-Overhead sind, sinnvoll, danke.