Die Kapazität eines Pipe-Puffers variiert je nach System (und kann sogar auf demselben System variieren). Ich bin nicht sicher, ob es eine schnelle, einfache und plattformübergreifende Möglichkeit gibt, die Kapazität eines Rohrs zu ermitteln.
Mac OS X verwendet beispielsweise standardmäßig eine Kapazität von 16384 Byte, kann jedoch auf 65336 Byte umschalten, wenn große Schreibvorgänge in die Pipe ausgeführt werden, oder auf die Kapazität einer einzelnen Systemseite, wenn bereits zu viel Kernelspeicher vorhanden ist Wird von Pipe-Puffern verwendet (siehe xnu/bsd/sys/pipe.h
und xnu/bsd/kern/sys_pipe.c
; da diese von FreeBSD stammen, kann das gleiche Verhalten auch dort auftreten).
Eine Manpage zu Linux Pipe (7) besagt, dass die Pipe-Kapazität seit Linux 2.6.11 65536 Byte und eine einzelne Systemseite davor beträgt (z. B. 4096 Byte auf (32-Bit) x86-Systemen). Der Code ( include/linux/pipe_fs_i.h
, und fs/pipe.c
) scheint 16 System-Seiten zu verwenden (dh 64 KB, wenn eine System-Seite 4 KB groß ist), aber der Puffer für jede Pipe kann über eine Fcntl in der Pipe angepasst werden (bis zu einer maximalen Kapazität, die standardmäßig 1048576 beträgt) Bytes, kann aber über /proc/sys/fs/pipe-max-size
)) geändert werden .
Hier ist eine kleine Bash / Perl- Kombination, mit der ich die Pipe-Kapazität auf meinem System getestet habe:
#!/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"
Ich habe festgestellt, dass es auf einem Mac OS X 10.6.7-System mit verschiedenen Schreibgrößen ausgeführt wird (beachten Sie die Änderung für Schreibvorgänge, die größer als 16 KB sind):
% /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
Dasselbe Skript unter 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
Hinweis: Der PIPE_BUF
in den C-Header-Dateien definierte Wert (und der Pfadkonfigurationswert für _PC_PIPE_BUF
) gibt nicht die Kapazität der Pipes an, sondern die maximale Anzahl von Bytes, die atomar geschrieben werden können (siehe POSIX- Schreibzugriff (2) ).
Zitat aus 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()
unter Linux. Ich hatte eine Weile nach Pufferprogrammen für Benutzer gesucht, weil ich dachte, die eingebauten Pipes hätten nicht genügend Puffer. Jetzt sehe ich, dass dies der Fall ist, wenn ich CAP_SYS_RESOURCE habe oder root bereit ist, die maximale Pipe-Größe zu erweitern. Da das, was ich möchte, nur auf einem bestimmten Linux-Computer (meinem) ausgeführt wird, sollte dies kein Problem sein.var=…
) der Ausgabe einer Befehlsersetzung ($(…)
), die gruppierte Befehle ({…}
, und(…)
) enthält. Es werden auch mehrere (seltenere) Umleitungen (dh0<&-
und3>&1
) verwendet.exec 0<&-
)). Der Abschlussbericht wirdtail -1
zusammen mit der Schreibgröße gesammelt ( ) und gedruckt.Diese Shell-Linie kann auch die Größe des Pipe-Puffers anzeigen:
(Senden von 1k Stücken an die blockierte Leitung, bis der Puffer voll ist) ... einige Testausgaben:
kürzester Bash-One-Liner mit printf:
quelle
(dd if=/dev/zero bs=1 | sleep 999) &
warten dann eine zweite undkillall -SIGUSR1 dd
gibt65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
- wie Sie Ihre Lösung, aber bei 1 Byte Auflösung;)dd
Befehl mit 16 KB blockiert. Auf Fedora 23/25 x86-64 blockiert es bei 64 KiB.dd if=/dev/zero bs=1 | sleep 999
in den Vordergrund rennen , eine Sekunde warten und dann drücken^C
. Wenn Sie einenkillall
dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
Hier sind einige weitere Alternativen, um die tatsächliche Pipe-Pufferkapazität nur mit Shell-Befehlen zu ermitteln:
quelle
getconf PIPE_BUF /
gedruckt,5120
was mit derulimit -a | grep pipe
Ausgabe übereinstimmt, aber nicht mit den 16 KB, nach denendd .. | sleep ...
blockiert wird.yes
Methode73728
anstelle der mitdd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
Dies ist ein schneller und schmutziger Hack auf Ubuntu 12.04, YMMV
quelle
Also habe ich auf meiner Linux-Box standardmäßig 8 * 512 = 4096-Byte-Pipes.
Solaris und viele andere Systeme haben eine ähnliche ulimit-Funktion.
quelle
(512 bytes, -p) 8
unter Fedora 23/25 und512 bytes, -p) 10
Solaris 10 gedruckt. Diese Werte stimmen nicht mit den Puffergrößen überein, die experimentell mit einer Blockierung ermittelt wurdendd
.Wenn Sie den Wert in Python> = 3.3 benötigen, ist dies eine einfache Methode (vorausgesetzt, Sie können call out to ausführen
dd
):quelle