Утилита для буферизации неограниченного количества данных в конвейере?

13

Есть ли утилита, которую я могу вставить в конвейер для разделения скоростей чтения и записи?

$ producer | buf | consumer

По сути, мне нужна утилита, bufкоторая считывает входные данные как можно быстрее, сохраняя их в памяти, чтобы они consumerмогли занимать приятное время и producerработать как можно быстрее.

Доктор Дж
источник
Я тоже хотел бы увидеть такое
Антти Хаапала
stdbufИнструмент , как представляется sizeпараметр. Я не уверен, что это работает, хотя.
CMCDragonkai

Ответы:

13

pv(Зритель труба) утилита может это сделать (с -Bопцией) и многое другое, в том числе предоставляя вам отчеты о ходе работ.

Дэвид Шварц
источник
Есть ли способ сделать это с неограниченным количеством данных? Насколько я могу судить, мне нужно указать число с -B, и если производитель опередит потребителя, он снова замедлится. Если вы находитесь в ситуации, когда есть несколько потребителей ( producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2), это может снова вызвать замедление.
Даниэль Х
Я использовал pvсотни раз и никогда не знал этого. Очень круто, спасибо!
Rucent88
pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null- Я ожидаю, что оба pvs на концах будут гладкими (хотя на 1 ГБ впереди). Это не работает таким образом, в отличие отmbuffer
Vi.
9

Вы можете использовать dd:

producer | dd obs=64K | consumer

Это доступно на каждом Unix.

Михал Шрайер
источник
+1 за использование стандартной утилиты, хотя pv, вероятно, лучше использовать (показывает прогресс).
Тотор
2
Это фактически отделяет скорость чтения и записи? Кажется, что ddхранится только один блок за раз, поэтому он просто задержит все на количество времени, необходимое для получения размера блока; Пожалуйста, поправьте меня, если я ошибаюсь. Кроме того, можно ли расширить эту буферизацию до неограниченного размера или только для того, что введено для размера блока?
Даниэль Х
@DanielH - теперь.
mikeserv
7

Посмотрите на mbuffer . Он может буферизовать в память или отображенный в память файл ( -t/ -T).

Стивен Пол Лесневски
источник
Как я и просил для других, есть ли способ сообщить ему, чтобы буферизовать столько, сколько необходимо, или он имеет максимальный размер? Есть ли концептуальная причина, по которой большинство этих программ имеют максимальные размеры и, например, не используют связанный список меньших буферов (или любую другую реализацию очереди произвольного размера)?
Даниэль Х
Вероятно, чтобы предотвратить ошибки нехватки памяти. Вы можете использовать опцию для установки очень большого буфера (4 ГБ или около того), если хотите (попробуйте).
Давид Балажич
1

Это в основном отрицательный ответ. Похоже, что ни dd, ни mbuffer, ни даже pvработает не все случаи, в частности, если скорость данных, генерируемых производителем, может сильно различаться. Я даю несколько тестов ниже. После ввода команды подождите около 10 секунд, затем введите >(чтобы перейти к концу данных, то есть дождаться окончания ввода).

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

Здесь после ввода >нужно подождать 5 секунд, что означает, что производитель (сценарий zsh) заблокирован перед sleep 5. Увеличение bsразмера, например, до 32 МБ, не меняет поведение, хотя буфер 32 МБ достаточно велик. Я подозреваю, что это потому, что ddблоки на выходе вместо того, чтобы продолжать с ввода. Использование oflag=nonblockне является решением, потому что это отбрасывает данные.

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

С mbuffer, проблема заключается в том , что первая строка (foo0) не появляется сразу. Кажется, нет никакой возможности включить буферизацию строки на входе.

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

С pvповедением похоже dd. Хуже того, я подозреваю, что это неправильно для терминала, так как иногда lessбольше не может получать входные данные от терминала; например, с ним нельзя выйти q.

vinc17
источник
0

Нестандартный ход: использование буфера сокетов.

Пример:

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

Для этого реализованы два дополнительных инструмента: buffered_pipeline и 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.
источник