에 주석으로 "| 진정한"나는 이유에 혼란 스러워요 메이크가하는 것과 같은 효과가 있습니다에서 "|| 사실" 사용자 CJM는 썼다 :
피해야 할 또 다른 이유 | true는 명령이 파이프 버퍼를 채우기에 충분한 출력을 생성하면 true를 읽기 위해 대기하는 것을 차단한다는 것입니다.
파이프 버퍼의 크기를 알 수있는 방법이 있습니까?
에 주석으로 "| 진정한"나는 이유에 혼란 스러워요 메이크가하는 것과 같은 효과가 있습니다에서 "|| 사실" 사용자 CJM는 썼다 :
피해야 할 또 다른 이유 | true는 명령이 파이프 버퍼를 채우기에 충분한 출력을 생성하면 true를 읽기 위해 대기하는 것을 차단한다는 것입니다.
파이프 버퍼의 크기를 알 수있는 방법이 있습니까?
답변:
파이프 버퍼의 용량은 시스템마다 다르며 심지어 동일한 시스템에서도 달라질 수 있습니다. 파이프 용량을 조회하는 빠르고 쉽고 크로스 플랫폼 방법이 있는지 확실하지 않습니다.
예를 들어, Mac OS X은 기본적으로 16384 바이트의 용량을 사용하지만 파이프에 큰 쓰기를 수행하는 경우 65336 바이트 용량으로 전환하거나 너무 많은 커널 메모리가 이미있는 경우 단일 시스템 페이지의 용량으로 전환 할 수 있습니다 파이프 버퍼에 의해 사용됩니다 ( xnu/bsd/sys/pipe.h
및 xnu/bsd/kern/sys_pipe.c
;은 FreeBSD에서 왔기 때문에 동일한 동작이 발생할 수 있습니다).
한 Linux pipe (7) 매뉴얼 페이지에 따르면 파이프 용량은 Linux 2.6.11 이후 65536 바이트이고 그 이전의 단일 시스템 페이지 (예 : (32 비트) x86 시스템의 경우 4096 바이트)입니다. 코드 ( include/linux/pipe_fs_i.h
, 및 fs/pipe.c
)는 16 개의 시스템 페이지 (예 : 시스템 페이지가 4 KiB 인 경우 64 KiB)를 사용하는 것처럼 보이지만 각 파이프의 버퍼는 파이프의 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 시스템에서 다양한 쓰기 크기로 실행 한 것으로 나타났습니다 (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
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 write (2) 참조 ).
/* 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가 있거나 루트가 최대 파이프 크기를 확장하려는 경우 그들이하는 것을 알 수 있습니다. 내가 원하는 것은 특정 Linux 컴퓨터 (광산)에서만 실행될 것이기 때문에 이것은 문제가되지 않습니다.
var=…
)입니다 . 또한 몇 가지 (흔하지 않은) 리디렉션 (예 : 및 )을 사용합니다. $(…)
{…}
(…)
0<&-
3>&1
exec 0<&-
)). 최종 보고서는 수집 tail -1
크기 ( )와 함께 수집 및 인쇄됩니다.
이 쉘 라인은 파이프 버퍼 크기도 표시 할 수 있습니다.
M=0; while true; do dd if=/dev/zero bs=1k count=1 2>/dev/null; \
M=$(($M+1)); echo -en "\r$M KB" 1>&2; done | sleep 999
(버퍼가 가득 찰 때까지 차단 된 파이프에 1k 청크 전송) ... 일부 테스트 출력 :
64K (intel-debian), 32K (aix-ppc), 64K (jslinux bellard.org) ...Ctrl+C.
printf를 사용하는 가장 짧은 bash-one-liner :
M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
(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 KiB에서 차단됩니다. Fedora 23/25 x86-64에서는 64 KiB로 차단됩니다.
dd if=/dev/zero bs=1 | sleep 999
는 포 그라운드에서 실행 하고 잠시 기다린 다음을 누릅니다 ^C
. Linux 및 BSD / macOS에서 하나의 라이너를 원한다면 (을 사용하는 것보다 강력 함 killall
)dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
다음은 쉘 명령 만 사용하여 실제 파이프 버퍼 용량을 탐색하는 몇 가지 추가 대안입니다.
# get pipe buffer size using Bash
yes produce_this_string_as_output | tee >(sleep 1) | wc -c
# portable version
( (sleep 1; exec yes produce_this_string_as_output) & echo $! ) |
(pid=$(head -1); sleep 2; kill "$pid"; wc -c </dev/stdin)
# get buffer size of named pipe
sh -c '
rm -f fifo
mkfifo fifo
yes produce_this_string_as_output | tee fifo | wc -c &
exec 3<&- 3<fifo
sleep 1
exec 3<&-
rm -f fifo
'
# Mac OS X
#getconf PIPE_BUF /
#open -e /usr/include/limits.h /usr/include/sys/pipe.h
# PIPE_SIZE
# BIG_PIPE_SIZE
# SMALL_PIPE_SIZE
# PIPE_MINDIRECT
getconf PIPE_BUF /
출력 5120
과 일치 ulimit -a | grep pipe
하지만 어떤 dd .. | sleep ...
블록 이후 16 KiB와 일치하지 않는 인쇄 .
yes
방법은 73728
다음과 같이 결정된 64 KiB 대신에 인쇄 됩니다.dd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
우분투 12.04의 YMMV에서 빠르고 더러운 해킹입니다.
cat >pipesize.c
#include <unistd.h>
#include <errno.h>
#include </usr/include/linux/fcntl.h>
#include <stdio.h>
void main( int argc, char *argv[] ){
int fd ;
long pipesize ;
if( argc>1 ){
// if command line arg, associate a file descriptor with it
fprintf( stderr, "sizing %s ... ", argv[1] );
fd = open( argv[1], O_RDONLY|O_NONBLOCK );
}else{
// else use STDIN as the file descriptor
fprintf( stderr, "sizing STDIN ... " );
fd = 0 ;
}
fprintf( stderr, "%ld bytes\n", (long)fcntl( fd, F_GETPIPE_SZ ));
if( errno )fprintf( stderr, "Uh oh, errno is %d\n", errno );
if( fd )close( fd );
}
gcc -o pipesize pipesize.c
mkfifo /tmp/foo
./pipesize /tmp/foo
>sizing /tmp/foo ... 65536 bytes
date | ./pipesize
>sizing STDIN ... 65536 bytes
$ ulimit -a | grep pipe
pipe size (512 bytes, -p) 8
따라서 Linux 상자에는 기본적으로 8 * 512 = 4096 바이트 파이프가 있습니다.
Solaris 및 기타 여러 시스템에는 유사한 ulimit 기능이 있습니다.
(512 bytes, -p) 8
Fedora 23/25 및 512 bytes, -p) 10
Solaris 10에서 인쇄 되며 이러한 값은 실험적으로 차단 된 버퍼 크기와 일치하지 않습니다 dd
.