Puffert es große Dateien durch Bash-Pipes?


7

Ich muss einen Befehl wie den folgenden verwenden:

$ cat large.input.file | process.py > large.output.file

Das Problem ist, dass es der Festplatte nicht schwer fällt, zwischen dem Lesen der Eingabedatei und dem Schreiben der Ausgabedatei zu springen.

Gibt es eine Möglichkeit, bash anzuweisen, bei dieser Art von Pipe einen großen Speicherpuffer zu verwenden?

Antworten:


4

Mach dir keine Sorgen. Das Betriebssystem übernimmt die Pufferung für Sie und ist normalerweise sehr gut darin.

Davon abgesehen: Wenn Sie process.py ändern können, können Sie Ihre eigene Pufferung implementieren. Wenn Sie process.py nicht ändern können, können Sie Ihre eigene buffer.py schreiben und so verwenden.

$ cat large.input.file | buffer.py | process.py | buffer.py > large.output.file

Wahrscheinlich wäre es viel einfacher, von einer RAM-Disk zu lesen und zu schreiben .


Habe ich Recht zu glauben, dass 'process.py' vom Python-Interpreter bereits automatisch gepuffert wird? Sie müssen keine eigene Pufferung implementieren, es sei denn, Sie möchten die Puffergröße überschreiben (mit 'python -u process.py', um den Python-Interpreter-E / A-Puffer auszuschalten)
Jonathan Hartley

8

Das Betriebssystem puffert die Ausgabe bis zu einem bestimmten Betrag, aber es kann immer noch zu einer starken Kopfbewegung kommen, wenn sich sowohl die Eingabe- als auch die Ausgabedatei auf demselben Laufwerk befinden, es sei denn, Sie führen process.pyeine eigene Pufferung durch.

Sie können catin Ihrem Beispiel den Pipe Viewer (pv) ersetzen (verfügbar in den meisten Standard-Repositorys und problemlos einzuhalten, wenn er nicht im Repo Ihrer Distribution enthalten ist), mit dem Sie festlegen können, dass mehr Puffer (mit den Optionen -B/ --buffer-bytes) und a angezeigt werden Fortschrittsbalken (es sei denn, Sie fordern ihn nicht auf), der für einen langen Vorgang sehr praktisch sein kann, wenn Sie process.pykeine eigenen Fortschrittsinformationen ausgeben. Wenn Daten von einem Ort auf einem Laufwerk an einen anderen Ort auf demselben Laufwerk übergeben werden, kann dies einen großen Unterschied machen, es sei denn, der Gesamtprozess ist in erster Linie an die CPU und nicht an die E / A gebunden.

Für einen 1-MB-Puffer könnten Sie also Folgendes tun:

pv -B 1m large.input.file | process.py > large.output.file

Ich benutze die pvganze Zeit für diese Art von Dingen, obwohl hauptsächlich für die Fortschrittsanzeige mehr als die einstellbare Puffergröße.

Eine andere Option ist die Verwendung des "Standard" (Standard in Bezug auf die allgemeine Verfügbarkeit, das Befehlszeilenformat unterscheidet sich ein wenig von den meisten gängigen Befehlen) dd, obwohl dies nicht über die Fortschrittsbalkenfunktion verfügt:

dd if=large.input.file bs=1048576 | process.py > large.output.file

Bearbeiten: ps. Anhänger weisen möglicherweise darauf hin, dass catdies in Ihrem Beispiel nicht erforderlich ist, da Folgendes genauso gut funktioniert und etwas effizienter ist:

process.py < large.input.file > large.output.file

Einige Leute bezeichnen die Beseitigung nicht bedingter Aufrufe catals "Demogifizierung", diese Leute sollten wahrscheinlich nicht ermutigt werden ...


3
Das Problem mit der "Demogifizierung" -Pedanterie ist, dass die nutzlose Verwendung von Katzen (UUOC) nicht wirklich nutzlos ist. Eine sehr wichtige Verwendung dafür sind Beispiele - sie machen sie viel klarer und leichter zu lesen und zu verstehen. Es ist auch praktisch, Ihre Pipeline mit einer kleinen Probe zu testen (mit Tail oder Head oder Grep oder was auch immer), bevor Sie die gesamte große Datei durchlaufen. Ersetzen Sie dann 'head' durch 'cat', wenn die Pipeline genau das tut, was Sie wollen.
Cas

Da würde ich zustimmen. Ich habe oft eine zusätzliche Katze an Ort und Stelle, da dies den visuellen Fluss (für diejenigen von uns, die natürlich von links nach rechts lesen) verbessern kann, insbesondere einer Zeile, die mehrere Umleitungen / Pipes umfasst, wodurch Skripte etwas klarer und daher etwas einfacher zu machen sind pflegen.
David Spillett

Wenn jemand wirklich , dass das Laufen denkt catzu teuer ist, sollten sie wahrscheinlich ihre Schale beheben , um automatisch zu ersetzen cat _single_file_ |mit < _single_file. Ich werde cat _single_file_ | stattdessen weiter schreiben .
Mikko Rantalainen

5

Gibt es nicht ein altes Unix-Tool namens "buffer"? Nicht, dass dies bei den heutigen Caching-Techniken erforderlich wäre - aber es ist da.


Ja, das gibt es. ich benutze es oft als schönen, flexiblen ersatz für dd.
Cas

Oh als dd Ersatz zu verwenden ist eine wirklich gute Idee - es sollte ziemlich viel schneller sein?
Hurikhan77

3

Ich glaube, dass das Problem, auf das sich der Benutzer bezieht, darin besteht, wie die Eingabe / Ausgabe im Allgemeinen in der UNIX / Linux-Welt funktioniert. Grundsätzlich kann für jeden UNIX / Linux-Prozess jeweils nur eine E / A-Operation ausstehen. Im Fall des Befehls cat im Beispiel liest der Befehl cat zuerst einige Daten, wartet auf deren Abschluss, schreibt dann die Daten und wartet auf deren Abschluss, bevor er fortfährt. Es gibt keine gleichzeitige E / A innerhalb eines Prozesses, daher wird die Pufferung nur zwischen den Lese- und Schreibvorgängen verwendet, um einfach vorübergehend einige Daten zu speichern.

Um die Arbeit zu beschleunigen, können die Eingabe und Ausgabe auf zwei verschiedene Prozesse aufgeteilt werden: einen Lese- und einen Schreibprozess sowie viel gemeinsam genutzten Speicher, der als Puffer zwischen den beiden Prozessen verwendet wird. Dies führt zu der gewünschten gleichzeitigen E / A und kann den Dateiübertragungsprozess beschleunigen.

Der von einem Benutzer angegebene Dienstprogrammpuffer implementiert diese von mir beschriebene gleichzeitige Methode. Ich habe das Pufferprogramm mit einem ziemlich großen gemeinsam genutzten Speicherpuffer verwendet, als ich eine Schnittstelle zu einem Bandlaufwerk für Sicherungen herstellte. Dies führte zu einer Verringerung der Übertragungszeit der Wanduhr um etwa 20%.

Die Verwendung des Pufferprogramms als Ersatz für den Befehl 'cat' kann zu einigen deutlichen Verbesserungen führen ... abhängig davon.

Genießen!


2

Versuchen Sie es mit diesem kleinen Python 2-Programm, das ich gerade zusammengestellt habe:

#! /usr/bin/python2
# This executable path is Gentoo-specific, you might need to change it yourself

import sys;

if sys.argv[1].endswith('K'):
   bytestoread = int(sys.argv[1].translate(None, 'K')) * 1024;
elif sys.argv[1].endswith('M'):
   bytestoread = int(sys.argv[1].translate(None, 'M')) * 1024 * 1024;
elif sys.argv[1].endswith('G'):
   bytestoread = int(sys.argv[1].translate(None, 'G')) * 1024 * 1024 * 1024;

while True:
   buffer = sys.stdin.read(bytestoread);
   if buffer == '':
      exit();
   sys.stdout.write(buffer);
   buffer = None;   # This one is for making sure the read buffer will get destroyed, otherwise we could bring our system to a halt if we have 8 GB of RAM, request a 5 GB buffer, and it ends up eating 10 GB of memory.

Um diese Datei zu verwenden, nennen Sie sie wie folgt:

cat large.input.file | process.py | buffer.py 2G > large.output.file

Sie können 2K verwenden, um 2 Kilobyte anzugeben, 2M für 2 Megabyte, 2G für 2 Gigabyte. Wenn Sie möchten, können Sie 2T für 2 Terabyte Puffer hinzufügen: 3

Ich bekomme dieses Problem immer wieder, wenn ich ein Image einer virtuellen Maschine mit komprimiere pigz -1, weil dies die Komprimierung so unglaublich schnell macht, dass die Festplatte gleichzeitig zu lesen und zu schreiben beginnt und der Prozess zum Stillstand kommt, wenn der Kopf der Festplatte zwischen den Eingabe- und Ausgabedateien schwirrt . Also habe ich dieses kleine Programm erstellt, das einen gigantischen Datenblock von der Standardeingabe liest, in die Standardausgabe schreibt und wiederholt. Wenn der Lesevorgang eine leere Zeichenfolge zurückgibt, wurde keine Standardeingabe mehr empfangen und das Skript wird beendet.


Zumindest theoretisch read()kann mit E_AGAINin UNIX-ähnlichen Systemen scheitern und Ihr Programm würde dann exit()vorzeitig. Überprüfen Sie immer explizit auf EOF.
Mikko Rantalainen

0

Es wird intelligent gepuffert, aber es gibt keine gute Möglichkeit, den Betrag zu optimieren.

Sie könnten ein Zwischenprogramm schreiben, das das gewünschte Caching ausführt und es von der Eingabe lesen lässt.


-1

Ihr Betriebssystem führt alle Arten von Caching für Dateien durch, bevor diese auf die Festplatte geschrieben werden, und führt auch das Caching für die gelesene Datei durch (im Allgemeinen wenn möglich vorauslesen). Lassen Sie das Betriebssystem das Puffern und Zwischenspeichern durchführen.

Bis Sie mithilfe von Tests und Profilen nachweisen können, dass die Festplatte der begrenzende Faktor in der Gleichung ist, lassen Sie sie am besten in Ruhe.

Wenn Sie process.py ändern können, können Sie statt direkt lesen / schreiben mit Pipes lesen / schreiben und stattdessen Puffer- und / oder Memmap-Dateien verwenden, um einen Teil der Last vom System zu entfernen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.