Utilité pour mettre en mémoire tampon une quantité illimitée de données dans un pipeline?


13

Existe-t-il un utilitaire que je peux coller dans un pipeline pour découpler les vitesses de lecture et d'écriture?

$ producer | buf | consumer

Fondamentalement, je veux un utilitaire bufqui lit son entrée le plus rapidement possible, le stockant en mémoire afin de consumerprendre son temps tout en producers'exécutant le plus rapidement possible.


J'aimerais aussi voir ça
Antti Haapala

L' stdbufoutil semble être un sizeparamètre. Je ne sais pas si cela fonctionne bien.
CMCDragonkai

Réponses:


13

L' pvutilitaire (visualiseur de tuyaux) peut le faire (avec l' -Boption) et bien plus encore, notamment en vous fournissant des rapports d'avancement.


Existe-t-il un moyen de le faire avec une quantité illimitée de données? Pour autant que je sache, je dois fournir un nombre avec -B et si le producteur devance aussi loin que le consommateur, le producteur ralentira à nouveau. Si vous êtes dans une situation où il y a plusieurs consommateurs ( producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2), cela peut entraîner à nouveau des ralentissements.
Daniel H

Je l'ai utilisé des pvcentaines de fois et je ne l'ai jamais su. Très génial, merci!
Rucent88

pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null- Je m'attends à ce que les deux pvextrémités soient lisses (bien que l'une ait 1 Go d'avance). Cela ne fonctionne pas de cette façon, contrairement àmbuffer
Vi.

9

vous pouvez utiliser dd:

producer | dd obs=64K | consumer

Il est disponible sur tous les Unix.


+1 pour l'utilisation de l'utilitaire standard, bien qu'il pvsoit probablement plus agréable à utiliser (indique la progression).
Totor

2
Cela découplera-t-il réellement la vitesse de lecture et d'écriture? Il semble que ddne stocke qu'un bloc à la fois, il retarderait donc tout le temps de production de la taille du bloc; Corrigez-moi si j'ai tort, s'il-vous plait. En outre, cette mise en mémoire tampon peut-elle être étendue à une taille illimitée, ou uniquement ce qui est entré pour la taille du bloc?
Daniel H

@DanielH - il le fait maintenant.
mikeserv

7

Jetez un oeil à mbuffer . Il peut mettre en mémoire tampon ou un fichier mappé en mémoire ( -t/ -T).


Comme je l'ai demandé pour les autres, existe-t-il un moyen de lui dire de mettre en mémoire tampon autant que nécessaire, ou a-t-il une taille maximale? Y a-t-il une raison conceptuelle pour laquelle la plupart de ces programmes ont des tailles maximales et n'utilisent pas, par exemple, une liste chaînée de tampons plus petits (ou toute autre implémentation de file d'attente de taille arbitraire)?
Daniel H

Probablement pour éviter les erreurs de mémoire insuffisante. Vous pouvez probablement utiliser une option pour définir un très grand tampon (4 Go environ) si vous le souhaitez (essayez-le).
David Balažic

1

Il s'agit essentiellement d'une réponse négative. Il apparaît que ni dd, ni mbuffer, ni même ne pvfonctionnent tous les cas, en particulier si le taux de données générées par le producteur peut varier considérablement. Je donne quelques tests ci-dessous. Après avoir tapé la commande, attendez environ 10 secondes, puis tapez >(pour aller à la fin des données, c'est-à-dire attendre la fin de l'entrée).

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

Ici, après avoir tapé >, il faut attendre 5 secondes, ce qui signifie que le producteur (script zsh) s'est bloqué avant le sleep 5. L'augmentation de la bstaille, par exemple à 32 Mo, ne change pas le comportement, bien que le tampon de 32 Mo soit suffisamment grand. Je soupçonne que c'est parce que les ddblocs sur la sortie au lieu de continuer avec l'entrée. L'utilisation oflag=nonblockn'est pas une solution car cela supprime les données.

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

Avec mbuffer, le problème est que la première ligne (foo0) n'apparaît pas immédiatement. Il ne semble pas y avoir d'option pour activer la mise en mémoire tampon de ligne en entrée.

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

Avec pv, le comportement est similaire à dd. Pire encore, je soupçonne que cela fait du tort au terminal car parfois lessil ne peut plus recevoir d'entrée du terminal; par exemple, on ne peut pas le quitter avec q.


0

Déplacement non standard: en utilisant des tampons de socket.

Exemple:

# 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] [       <=>                   ]

Implémentation de deux outils supplémentaires pour cela: buffered_pipeline et 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] [         <=>      ]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.