파이프 버퍼는 얼마나 큽니까?

파이프 버퍼는 얼마나 큽니까?

코멘트로메이크파일의 "| true"가 "|| true"와 동일한 효과를 갖는 이유가 무엇인지 혼란스럽습니다.사용자웨스트젬썼다:

피해야 할 또 다른 이유 | true는 명령이 파이프 버퍼를 채울 만큼 충분한 출력을 생성하는 경우 true를 읽기 위해 대기하는 것을 차단한다는 것입니다.

파이프 버퍼의 크기를 알 수 있는 방법이 있나요?

답변1

파이프 버퍼의 용량은 시스템마다 다릅니다(동일한 시스템에서도 다를 수 있음). 파이프의 용량을 찾는 빠르고 쉬운 크로스 플랫폼 방법이 있는지 잘 모르겠습니다.

예를 들어, Mac OS . 파이프 버퍼에서 사용됩니다(참조:xnu/bsd/sys/pipe.h, 그리고xnu/bsd/kern/sys_pipe.c; FreeBSD에서 왔기 때문에 동일한 동작이 발생할 수 있습니다.

리눅스파이프(7)매뉴얼 페이지Linux 2.6.11에서는 파이프 용량을 65536바이트로 표시하고 그 이전에는 단일 시스템 페이지(예: (32비트) x86 시스템에서 4096바이트)로 표시합니다. 코드(include/linux/pipe_fs_i.h, 그리고fs/pipe.c)는 16개의 시스템 페이지(즉, 시스템 페이지가 4KiB인 경우 64KiB)를 사용하는 것으로 보이지만 파이프당 버퍼는 통과할 수 있습니다.포캉트르파이프에(최대 용량은 기본적으로 1048576바이트이지만 변경될 수 있음 /proc/sys/fs/pipe-max-size))


여기 조금세게 때리다/진주내 시스템의 파이프 용량을 테스트하는 데 사용한 조합은 다음과 같습니다.

#!/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_BUFC 헤더 파일에 정의된 값(및경로 구성value _PC_PIPE_BUF), 파이프의 용량을 지정하는 것이 아니라 원자적으로 쓸 수 있는 최대 바이트 수를 지정합니다(참조:POSIX쓰기(2)).

에서 인용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.  */

답변2

이 쉘 라인은 파이프 버퍼 크기도 표시할 수 있습니다.

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

답변3

다음은 쉘 명령만 사용하여 실제 파이프 버퍼 용량을 탐색하는 몇 가지 추가 대안입니다.

# 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

답변4

Python >= 3.3의 값이 필요한 경우 간단한 방법은 다음과 같습니다(call out을 실행할 수 있다고 가정 dd).

from subprocess import Popen, PIPE, TimeoutExpired
p = Popen(["dd", "if=/dev/zero", "bs=1"], stdin=PIPE, stdout=PIPE)
try: 
    p.wait(timeout=1)
except TimeoutExpired: 
    p.kill()
    print(len(p.stdout.read()))

관련 정보