Dienstprogramm zum Puffern einer unbegrenzten Datenmenge in einer Pipeline?

13

Gibt es ein Dienstprogramm, das ich in eine Pipeline stecken kann, um Lese- und Schreibgeschwindigkeiten zu entkoppeln?

$ producer | buf | consumer

Grundsätzlich möchte ich ein Dienstprogramm buf, das seine Eingabe so schnell wie möglich liest und sie im Speicher speichert, damit es consumerseine schöne Zeit in Anspruch nimmt, während es producerso schnell wie möglich ausgeführt wird.

Doktor J
quelle
Das würde ich auch gerne sehen
Antti Haapala
Das stdbufWerkzeug scheint ein sizeParameter zu sein. Ich bin mir nicht sicher, ob es funktioniert.
CMCDragonkai

Antworten:

13

Das pvDienstprogramm (Pipe Viewer) kann dies (mit der -BOption) und vieles mehr tun , einschließlich der Erstellung von Fortschrittsberichten.

David Schwartz
quelle
Gibt es eine Möglichkeit, dies mit einer unbegrenzten Datenmenge zu tun? Soweit ich das beurteilen kann, muss ich eine Zahl mit -B angeben, und wenn der Produzent dem Verbraucher so weit voraus ist, wird der Produzent wieder langsamer. Wenn Sie sich in einer Situation befinden, in der sich mehrere Verbraucher ( producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2) befinden, kann dies erneut zu einer Verlangsamung führen.
Daniel H
Ich habe es pvhunderte Male benutzt und wusste es nie. Sehr genial, danke!
Rucent88
pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null- Ich erwarte, dass beide pvEnden glatt sind (obwohl eine 1 GB voraus ist). Anders als beimbuffer
Vi
9

Sie können verwenden dd:

producer | dd obs=64K | consumer

Es ist auf jedem Unix verfügbar.

Michał Šrajer
quelle
+1 für die Verwendung des Standarddienstprogramms, obwohl pvdie Verwendung wahrscheinlich besser ist (zeigt den Fortschritt an).
Totor
2
Entkoppelt das tatsächlich die Lese- und Schreibgeschwindigkeit? Es scheint, als würde immer ddnur ein Block gleichzeitig gespeichert. Es würde also alles nur um die Zeit verzögern, die erforderlich ist, um die Blockgröße zu erzeugen. Bitte korrigieren Sie mich, wenn ich falsch liege. Kann diese Pufferung auch auf eine unbegrenzte Größe erweitert werden oder nur, was auch immer für die Blockgröße eingegeben wurde?
Daniel H
@DanielH - das tut es jetzt.
mikeserv
7

Schauen Sie sich mbuffer an . Es kann in den Speicher oder in eine Speicherzuordnungsdatei ( -t/ -T) puffern .

Stephen Paul Lesniewski
quelle
Wie ich für die anderen gefragt habe, gibt es eine Möglichkeit, es anzuweisen, so viel wie nötig zu puffern, oder hat es eine maximale Größe? Gibt es einen begrifflichen Grund, warum die meisten dieser Programme maximale Größen haben und beispielsweise keine verknüpfte Liste kleinerer Puffer verwenden (oder keine andere Implementierung einer Warteschlange mit beliebiger Größe)?
Daniel H
Wahrscheinlich, um Speicherfehler zu vermeiden. Sie können wahrscheinlich eine Option verwenden, um einen sehr großen Puffer (4 GB oder so) festzulegen, wenn Sie dies möchten (versuchen Sie es).
David Balažic
1

Dies ist im Grunde eine negative Antwort. Es scheint, dass weder ddnoch mbuffernoch gar nichts pvfunktioniert, insbesondere wenn die vom Hersteller generierte Datenrate sehr unterschiedlich sein kann. Ich gebe einige Testfälle unten. Warten Sie nach der Eingabe des Befehls etwa 10 Sekunden und geben Sie dann Folgendes ein >(um zum Ende der Daten zu gelangen, dh bis zum Ende der Eingabe zu warten).

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | dd bs=64K | less

Hier muss man nach dem Tippen >5 Sekunden warten, was bedeutet, dass der Produzent (zsh script) vor dem blockiert hat sleep 5. Das Erhöhen der bsGröße auf z. B. 32 MB ändert nichts am Verhalten, obwohl der 32-MB-Puffer groß genug ist. Ich vermute, das liegt daran, dass die ddAusgabe blockiert wird, anstatt mit der Eingabe fortzufahren. Verwenden oflag=nonblockist keine Lösung, da hierdurch Daten verworfen werden.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | mbuffer -q | less

Mit mbufferist das Problem , dass die erste Zeile (foo0) nicht sofort angezeigt. Es scheint keine Option zu geben, um die Zeilenpufferung bei der Eingabe zu aktivieren.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | pv -q -B 32m | less

Mit pvist das Verhalten ähnlich dd. Schlimmer noch, ich vermute, dass es falsche Dinge mit dem Terminal tut, da manchmal lesskeine Eingaben mehr vom Terminal empfangen werden können. zum Beispiel kann man es nicht mit beenden q.

vinc17
quelle
0

Nicht-Standard-Verschiebung: Verwenden von Socket-Puffern.

Beispiel:

# echo 2000000000 > /proc/sys/net/core/wmem_max
$ socat -u system:'pv -c -N i /dev/zero',sndbuf=1000000000 - | pv -L 100k -c -N o > /dev/null
        i:  468MB 0:00:16 [ 129kB/s] [  <=>                        ]
        o: 1.56MB 0:00:16 [ 101kB/s] [       <=>                   ]

Dazu wurden zwei zusätzliche Tools implementiert: buffered_pipeline und mapopentounixsocket

$ ./buffered_pipeline ! pv -i 10 -c -N 1 /dev/zero ! $((20*1000*1000)) ! pv -i 10 -L 100k -c -N 2 ! > /dev/zero
        1: 13.4MB 0:00:40 [ 103kB/s] [         <=>      ]
        2: 3.91MB 0:00:40 [ 100kB/s] [         <=>      ]
Vi.
quelle