A capacidade de um buffer de tubo varia entre os sistemas (e pode até variar no mesmo sistema). Não tenho certeza de que exista uma maneira rápida, fácil e multiplataforma de apenas pesquisar a capacidade de um tubo.
O Mac OS X, por exemplo, usa uma capacidade de 16384 bytes por padrão, mas pode alternar para capacidades de 65336 bytes se forem feitas grandes gravações no canal ou alternará para a capacidade de uma única página do sistema se já houver muita memória do kernel sendo usado por buffers de pipe (veja xnu/bsd/sys/pipe.h
, e xnu/bsd/kern/sys_pipe.c
; como são do FreeBSD, o mesmo comportamento também pode acontecer lá).
Uma página do manual pipe (7) do Linux diz que a capacidade do pipe é de 65536 bytes desde o Linux 2.6.11 e uma única página do sistema anterior (por exemplo, 4096 bytes em sistemas x86 (32 bits)). O código ( include/linux/pipe_fs_i.h
, e fs/pipe.c
) parece usar 16 páginas do sistema (ou seja, 64 KiB se uma página do sistema for 4 KiB), mas o buffer de cada canal pode ser ajustado através de um fcntl no canal (até uma capacidade máxima padrão 1048576 bytes, mas pode ser alterado via /proc/sys/fs/pipe-max-size
)).
Aqui está uma pequena combinação de bash / perl que eu usei para testar a capacidade do tubo no meu sistema:
#!/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"
Aqui está o que eu achei executando-o com vários tamanhos de gravação em um sistema Mac OS X 10.6.7 (observe a alteração para gravações maiores que 16KiB):
% /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
O mesmo script no 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
Nota: O PIPE_BUF
valor definido nos arquivos de cabeçalho C (e o valor pathconf para _PC_PIPE_BUF
) não especifica a capacidade dos pipes, mas o número máximo de bytes que podem ser gravados atomicamente (consulte POSIX write (2) ).
Citação de 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()
no Linux; Eu havia passado algum tempo procurando programas de buffer no espaço do usuário porque achava que os pipes internos não tinham um buffer grande o suficiente. Agora vejo que sim, se eu tiver CAP_SYS_RESOURCE ou o root estiver disposto a expandir o tamanho máximo do tubo. Como o que eu quero será executado apenas em um computador Linux específico (o meu), isso não deve ser um problema.var=…
) da saída de uma substituição de comando ($(…)
) que inclui comandos agrupados ({…}
, e(…)
). Ele também usa vários redirecionamentos ( menos comuns) (ie0<&-
e3>&1
).exec 0<&-
)). O relatório final é coletado (tail -1
) e impresso junto com o tamanho da gravação.essa linha de shell também pode mostrar o tamanho do buffer do tubo:
(enviando pedaços de 1k ao tubo bloqueado até o buffer ficar cheio) ... algumas saídas de teste:
menor bash-one-liner usando printf:
fonte
(dd if=/dev/zero bs=1 | sleep 999) &
em seguida, espere um segundo ekillall -SIGUSR1 dd
dá65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
- o mesmo que a sua solução, mas a resolução de 1 byte;)dd
comando é bloqueado em 16 KiB. No Fedora 23/25 x86-64, ele bloqueia em 64 KiB.dd if=/dev/zero bs=1 | sleep 999
em primeiro plano, esperar um segundo e pressionar^C
. Se você queria um one-liner em Linux e BSD / MacOS (mais robusto do que usarkillall
):dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
Aqui estão algumas alternativas adicionais para explorar a capacidade real do buffer de tubo usando apenas comandos shell:
fonte
getconf PIPE_BUF /
imprime5120
que corresponde àulimit -a | grep pipe
saída, mas não aos 16 KiB após os quaisdd .. | sleep ...
bloqueia.yes
método imprime73728
em vez dos 64 KiB determinada comdd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
Este é um hack rápido e sujo no Ubuntu 12.04, YMMV
fonte
Então, na minha caixa Linux, tenho 8 * 512 = 4096 bytes por padrão.
Solaris e muitos outros sistemas têm uma função ulimit semelhante.
fonte
(512 bytes, -p) 8
no Fedora 23/25 e512 bytes, -p) 10
no Solaris 10 - e esses valores não correspondem aos tamanhos de buffer derivados experimentalmente com um bloqueiodd
.Se você precisar do valor em Python> = 3.3, aqui está um método simples (supondo que você possa executar a chamada
dd
):fonte