Емкость конвейерного буфера варьируется в зависимости от системы (и может даже различаться в одной и той же системе). Я не уверен, что существует быстрый, простой и кроссплатформенный способ просто проверить емкость трубы.
Например, Mac OS X по умолчанию использует емкость 16384 байта, но может переключиться на емкость 65336 байтов, если в канал выполняется большая запись, или переключится на емкость одной системной страницы, если уже слишком много памяти ядра используется конвейерными буферами (см. xnu/bsd/sys/pipe.h
, и xnu/bsd/kern/sys_pipe.c
, поскольку они взяты из FreeBSD, там тоже может происходить то же самое).
Одна справочная страница Linux pipe (7) сообщает, что емкость канала составляет 65536 байт начиная с Linux 2.6.11 и одну системную страницу до этого (например, 4096 байт в (32-разрядных) системах x86). Код ( include/linux/pipe_fs_i.h
, и fs/pipe.c
), по-видимому, использует 16 системных страниц (т. Е. 64 КиБ, если системная страница равна 4 КиБ), но буфер для каждого канала можно настроить с помощью fcntl на канале (до максимальной емкости, которая по умолчанию равна 1048576 байт, но можно изменить через /proc/sys/fs/pipe-max-size
)).
Вот небольшая комбинация bash / perl, которую я использовал для проверки производительности канала в моей системе:
#!/bin/bash
test $# -ge 1 || { echo "usage: $0 write-size [wait-time]"; exit 1; }
test $# -ge 2 || set -- "$@" 1
bytes_written=$(
{
exec 3>&1
{
perl -e '
$size = $ARGV[0];
$block = q(a) x $size;
$num_written = 0;
sub report { print STDERR $num_written * $size, qq(\n); }
report; while (defined syswrite STDOUT, $block) {
$num_written++; report;
}
' "$1" 2>&3
} | (sleep "$2"; exec 0<&-);
} | tail -1
)
printf "write size: %10d; bytes successfully before error: %d\n" \
"$1" "$bytes_written"
Вот что я обнаружил, запустив его с различными размерами записи в системе Mac OS X 10.6.7 (обратите внимание на изменение для записи размером более 16 КБ):
% /bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 16384
write size: 2; bytes successfully before error: 16384
write size: 4; bytes successfully before error: 16384
write size: 8; bytes successfully before error: 16384
write size: 16; bytes successfully before error: 16384
write size: 32; bytes successfully before error: 16384
write size: 64; bytes successfully before error: 16384
write size: 128; bytes successfully before error: 16384
write size: 256; bytes successfully before error: 16384
write size: 512; bytes successfully before error: 16384
write size: 1024; bytes successfully before error: 16384
write size: 2048; bytes successfully before error: 16384
write size: 4096; bytes successfully before error: 16384
write size: 8192; bytes successfully before error: 16384
write size: 16384; bytes successfully before error: 16384
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
Тот же скрипт в Linux 3.19:
/bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 65536
write size: 2; bytes successfully before error: 65536
write size: 4; bytes successfully before error: 65536
write size: 8; bytes successfully before error: 65536
write size: 16; bytes successfully before error: 65536
write size: 32; bytes successfully before error: 65536
write size: 64; bytes successfully before error: 65536
write size: 128; bytes successfully before error: 65536
write size: 256; bytes successfully before error: 65536
write size: 512; bytes successfully before error: 65536
write size: 1024; bytes successfully before error: 65536
write size: 2048; bytes successfully before error: 65536
write size: 4096; bytes successfully before error: 65536
write size: 8192; bytes successfully before error: 65536
write size: 16384; bytes successfully before error: 65536
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
Примечание. PIPE_BUF
Значение, определенное в заголовочных файлах C (и значение pathconf для _PC_PIPE_BUF
), указывает не емкость каналов, а максимальное количество байтов, которые могут быть записаны атомарно (см. Запись POSIX (2) ).
Цитата из include/linux/pipe_fs_i.h
:
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
fcntl()
о Linux; Я потратил некоторое время на поиск программ буферизации в пользовательском пространстве, потому что думал, что встроенные каналы не имеют достаточно большого буфера. Теперь я вижу, что они делают, если у меня есть CAP_SYS_RESOURCE или root хочет расширить максимальный размер канала. Поскольку то, что я хочу, будет работать только на определенном компьютере с Linux (мой), это не должно быть проблемой.var=…
) для вывода команды substitution ($(…)
), которая включает в себя сгруппированные команды ({…}
, и(…)
). Он также использует несколько (менее распространенных) перенаправлений (то есть0<&-
и3>&1
).exec 0<&-
)). Окончательный отчет собирается (tail -1
) и печатается вместе с размером записи.эта оболочка также может показывать размер буфера канала:
(отправка кусков по 1k в заблокированный канал до заполнения буфера) ... некоторые результаты теста:
кратчайший bash-one-liner с использованием printf:
источник
(dd if=/dev/zero bs=1 | sleep 999) &
затем подождите секунду иkillall -SIGUSR1 dd
выдаст65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
- то же, что и ваше решение, но с разрешением 1 байт;)dd
команда блокируется в 16 КиБ. На Fedora 23/25 x86-64 он блокируется на 64 КиБ.dd if=/dev/zero bs=1 | sleep 999
на переднем плане, подождать секунду, а затем нажать^C
. Если вам нужнаkillall
dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
Вот еще несколько альтернатив для изучения фактической емкости буферного канала с использованием только команд оболочки:
источник
getconf PIPE_BUF /
печатает,5120
который соответствуетulimit -a | grep pipe
выводу, но не соответствует 16 КиБ, после чегоdd .. | sleep ...
блоки.yes
метод печатает73728
вместо 64 КиБ, определенных с помощьюdd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
Это быстрый и грязный взлом на Ubuntu 12.04, YMMV
источник
Так что в моем Linux-боксе у меня по умолчанию 8 * 512 = 4096 байт.
Solaris и многие другие системы имеют аналогичную функцию ulimit.
источник
(512 bytes, -p) 8
на Fedora 23/25 и512 bytes, -p) 10
на Solaris 10 - и эти значения не соответствуют размерам буфера, экспериментально полученным с блокировкойdd
.Если вам нужно значение в Python> = 3.3, вот простой метод (при условии, что вы можете запустить call to
dd
):источник