La capacidad de un buffer de tubería varía entre sistemas (e incluso puede variar en el mismo sistema). No estoy seguro de que haya una manera rápida, fácil y multiplataforma para buscar la capacidad de una tubería.
Mac OS X, por ejemplo, usa una capacidad de 16384 bytes de manera predeterminada, pero puede cambiar a capacidades de 65336 bytes si se realiza una gran escritura en la tubería, o cambiará a una capacidad de una sola página del sistema si ya hay demasiada memoria del núcleo siendo utilizado por los buffers de tubería (ver xnu/bsd/sys/pipe.h
, y xnu/bsd/kern/sys_pipe.c
; dado que estos son de FreeBSD, el mismo comportamiento también puede ocurrir allí).
Una página del comando man Linux pipe (7) dice que la capacidad de la tubería es 65536 bytes desde Linux 2.6.11 y una sola página del sistema anterior (por ejemplo, 4096 bytes en sistemas x86 (32 bits)). El código ( include/linux/pipe_fs_i.h
y fs/pipe.c
) parece usar 16 páginas del sistema (es decir, 64 KiB si una página del sistema es 4 KiB), pero el búfer para cada tubería se puede ajustar a través de un fcntl en la tubería (hasta una capacidad máxima que por defecto es 1048576 bytes, pero se puede cambiar a través de /proc/sys/fs/pipe-max-size
)).
Aquí hay una pequeña combinación bash / perl que utilicé para probar la capacidad de la tubería en mi 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"
Esto es lo que encontré ejecutándolo con varios tamaños de escritura en un sistema Mac OS X 10.6.7 (tenga en cuenta el cambio para escrituras de más de 16 KB):
% /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
El mismo script en 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: El PIPE_BUF
valor definido en los archivos de encabezado C (y el valor de pathconf para _PC_PIPE_BUF
) no especifica la capacidad de las canalizaciones, sino el número máximo de bytes que pueden escribirse atómicamente (consulte POSIX write (2) ).
Cita 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()
en Linux; Pasé un tiempo buscando programas de almacenamiento en búfer del espacio de usuario porque pensé que las tuberías incorporadas no tenían un búfer lo suficientemente grande. Ahora veo que sí, si tengo CAP_SYS_RESOURCE o root está dispuesto a expandir el tamaño máximo de tubería. Como lo que quiero solo se ejecutará en una computadora Linux específica (la mía), esto no debería ser un problema.var=…
) de la salida de una sustitución de comando ($(…)
) que incluye comandos agrupados ({…}
, y(…)
). También utiliza varias redirecciones ( menos comunes) (es decir,0<&-
y3>&1
).exec 0<&-
)). El informe final se recopila (tail -1
) y se imprime junto con el tamaño de escritura.esta línea de shell también puede mostrar el tamaño del buffer de tubería:
(enviando trozos de 1k a la tubería bloqueada hasta que el buffer esté lleno) ... algunas salidas de prueba:
el más corto bash-one-liner usando printf:
fuente
(dd if=/dev/zero bs=1 | sleep 999) &
luego espera un segundo ykillall -SIGUSR1 dd
da65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
, igual que tu solución, pero con una resolución de 1 byte;)dd
comando se bloquea a 16 KiB. En Fedora 23/25 x86-64, se bloquea a 64 KiB.dd if=/dev/zero bs=1 | sleep 999
en primer plano, esperar un segundo y luego presionar^C
. Si quería una línea en Linux y BSD / macOS (más robusto que usarkillall
):dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
Aquí hay algunas alternativas adicionales para explorar la capacidad real del búfer de tubería utilizando solo comandos de shell:
fuente
getconf PIPE_BUF /
imprime lo5120
que coincide con laulimit -a | grep pipe
salida pero no con los 16 KiB después de los cuales sedd .. | sleep ...
bloquea.yes
método se imprime en73728
lugar del 64 KiB determinado condd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
Este es un truco rápido y sucio en Ubuntu 12.04, YMMV
fuente
Entonces, en mi caja de Linux tengo 8 * 512 = 4096 bytes de tuberías por defecto.
Solaris y muchos otros sistemas tienen una función ulimit similar.
fuente
(512 bytes, -p) 8
en Fedora 23/25 y512 bytes, -p) 10
en Solaris 10, y esos valores no coinciden con los tamaños de búfer derivados experimentalmente con un bloqueodd
.Si necesita el valor en Python> = 3.3, aquí hay un método simple (suponiendo que pueda ejecutar call to
dd
):fuente