Pojemność bufora potoku różni się w zależności od systemu (i może nawet różnić się w tym samym systemie). Nie jestem pewien, czy istnieje szybki, łatwy i wieloplatformowy sposób, aby po prostu sprawdzić pojemność rury.
Na przykład Mac OS X domyślnie wykorzystuje pojemność 16384 bajtów, ale może przełączyć się na pojemność 65336 bajtów, jeśli do potoku wprowadzono duży zapis, lub przełączy się na pojemność pojedynczej strony systemowej, jeśli już jest za dużo pamięci jądra używane przez bufory potokowe (patrz xnu/bsd/sys/pipe.h
i xnu/bsd/kern/sys_pipe.c
; ponieważ pochodzą one z FreeBSD, to samo może się tam zdarzyć).
Jedna strona podręcznika systemowego potoku Linux (7) mówi, że pojemność potoku wynosi 65536 bajtów od Linuksa 2.6.11, a wcześniej jedna strona systemowa (np. 4096 bajtów w systemach (32-bitowych) x86). Wydaje się, że kod ( include/linux/pipe_fs_i.h
i fs/pipe.c
) używa 16 stron systemowych (tj. 64 KiB, jeśli strona systemowa ma 4 KiB), ale bufor dla każdej potoki można regulować za pomocą fcntl na potoku (do maksymalnej pojemności, która domyślnie wynosi 1048576 bajtów, ale można je zmienić za pomocą /proc/sys/fs/pipe-max-size
)).
Oto mała kombinacja bash / perl , której użyłem do przetestowania pojemności rur w moim systemie:
#!/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"
Oto, co znalazłem, uruchamiając go z różnymi rozmiarami zapisu w systemie Mac OS X 10.6.7 (zwróć uwagę na zmianę zapisu większą niż 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
Ten sam skrypt w systemie 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
Uwaga: PIPE_BUF
Wartość zdefiniowana w plikach nagłówka C (i wartość pathconf dla _PC_PIPE_BUF
) nie określa pojemności potoków, ale maksymalną liczbę bajtów, które można zapisać atomowo (patrz zapis POSIX (2) ).
Cytat z 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()
o Linuksie; Spędziłem trochę czasu na poszukiwaniu programów buforujących przestrzeń użytkownika, ponieważ myślałem, że wbudowane potoki nie mają wystarczająco dużego bufora. Teraz widzę, że tak, jeśli mam CAP_SYS_RESOURCE lub root chce zwiększyć maksymalny rozmiar rury. Ponieważ to, czego chcę, będzie działało tylko na określonym komputerze z Linuksem (moim), nie powinno to stanowić problemu.var=…
) wyniku funkcji podstawiania poleceń ($(…)
), która obejmuje polecenia zgrupowane ({…}
, i(…)
). Wykorzystuje także kilka (mniej powszechnych) przekierowań (tj.0<&-
I3>&1
).exec 0<&-
)). Raport końcowy jest zbierany (tail -1
) i drukowany wraz z rozmiarem zapisu.ta linia powłoki może również pokazywać rozmiar bufora potoku:
(wysyłanie fragmentów 1k do zablokowanej rury, aż bufor się zapełni) ... niektóre wyniki testu:
najkrótsza bash-one-liner przy użyciu printf:
źródło
(dd if=/dev/zero bs=1 | sleep 999) &
następnie poczekaj sekundę ikillall -SIGUSR1 dd
daje65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s
- tak samo jak twoje rozwiązanie, ale w rozdzielczości 1 bajta;)dd
komenda blokuje przy 16 KiB. W Fedorze 23/25 x86-64 blokuje przy 64 KiB.dd if=/dev/zero bs=1 | sleep 999
na pierwszym planie, odczekać sekundę, a następnie nacisnąć^C
. Jeśli chciałeś mieć Linuksa na Linuksie i BSD / macOS (bardziej solidny niż przy użyciukillall
):dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
Oto kilka innych możliwości sprawdzenia rzeczywistej pojemności bufora potoku przy użyciu tylko poleceń powłoki:
źródło
getconf PIPE_BUF /
drukuje,5120
który pasuje doulimit -a | grep pipe
wyniku, ale nie pasuje do 16 KiB, po którymdd .. | sleep ...
blokuje.yes
metoda drukuje73728
zamiast 64 KiB ustalonych za pomocądd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
To szybki i brudny hack na Ubuntu 12.04, YMMV
źródło
Więc na moim Linux-ie mam domyślnie 8 * 512 = 4096 bajtów potoków.
Solaris i wiele innych systemów ma podobną funkcję ulimit.
źródło
(512 bytes, -p) 8
na Fedorze 23/25 i512 bytes, -p) 10
Solarisie 10 - i te wartości nie pasują do rozmiarów buforów eksperymentalnie wyprowadzonych z blokowaniemdd
.Jeśli potrzebujesz wartości w Pythonie> = 3.3, oto prosta metoda (zakładając, że możesz uruchomić call out
dd
):źródło