it-swarm-vi.com

Làm thế nào lớn là bộ đệm ống?

Như một nhận xét trong Tôi bối rối không hiểu tại sao "| true" trong tệp tạo tệp có tác dụng tương tự như "|| true" người dùng cjm đã viết:

Một lý do khác để tránh | đúng là nếu lệnh tạo ra đầu ra đủ để lấp đầy bộ đệm ống, nó sẽ chặn chờ đúng để đọc nó.

Chúng ta có một số cách để tìm ra kích thước của bộ đệm ống là gì?

150
Kit Sunde

Công suất của bộ đệm ống khác nhau giữa các hệ thống (và thậm chí có thể thay đổi trên cùng một hệ thống). Tôi không chắc chắn có một cách nhanh chóng, dễ dàng và đa nền tảng để chỉ tìm kiếm công suất của một đường ống.

Ví dụ, Mac OS X sử dụng dung lượng 16384 byte theo mặc định, nhưng có thể chuyển sang dung lượng 65336 byte nếu ghi lớn được thực hiện cho đường ống hoặc sẽ chuyển sang dung lượng của một trang hệ thống nếu đã có quá nhiều bộ nhớ kernel đang được sử dụng bởi bộ đệm ống (xem xnu/bsd/sys/pipe.hxnu/bsd/kern/sys_pipe.c ; vì đây là từ FreeBSD, hành vi tương tự cũng có thể xảy ra ở đó).

Một trang Linux pipe (7) nói rằng dung lượng ống là 65536 byte kể từ Linux 2.6.11 và một trang hệ thống trước đó (ví dụ 4096 byte trên các hệ thống x86 (32 bit)). Mật mã ( include/linux/pipe_fs_i.hfs/pipe.c ) dường như sử dụng 16 trang hệ thống (tức là 64 KiB nếu một trang hệ thống là 4 KiB), nhưng bộ đệm cho mỗi ống có thể được điều chỉnh thông qua một fcntl trên đường ống (tối đa dung lượng tối đa mặc định là 1048576 byte, nhưng có thể được thay đổi thông qua /proc/sys/fs/pipe-max-size)).


Đây là một kết hợp bash / Perl mà tôi đã sử dụng để kiểm tra dung lượng ống trên hệ thống của tôi:

#!/bin/bash
test $# -ge 1 || { echo "usage: $0 write-size [wait-time]"; exit 1; }
test $# -ge 2 || set -- "[email protected]" 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"

Đây là những gì tôi tìm thấy khi chạy nó với các kích cỡ ghi khác nhau trên hệ thống Mac OS X 10.6.7 (lưu ý thay đổi đối với ghi lớn hơn 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

Kịch bản tương tự trên 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

Lưu ý: PIPE_BUF giá trị được xác định trong tệp tiêu đề C (và giá trị pathconf cho _PC_PIPE_BUF), không chỉ định dung lượng của đường ống, nhưng số byte tối đa có thể được viết nguyên tử (xem POSIX write (2) ).

Trích dẫn từ 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.  */
147
Chris Johnsen

dòng Shell này cũng có thể hiển thị kích thước bộ đệm ống:

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

(gửi các khối 1k đến đường ống bị chặn cho đến khi bộ đệm đầy) ... một số kết quả thử nghiệm:

64K (intel-debian), 32K (aix-ppc), 64K (jslinux bellard.org)      ...Ctrl+C.

bash-one-liner ngắn nhất sử dụng printf:

M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
36
Asain Kujovic

Dưới đây là một số lựa chọn thay thế khác để khám phá dung lượng bộ đệm ống thực tế chỉ bằng các lệnh Shell:

# 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
8
chan

Đây là một bản hack nhanh và bẩn trên Ubuntu 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
6
Jeff

Nếu bạn cần giá trị trong Python> = 3.3, đây là một phương thức đơn giản (giả sử bạn có thể chạy lệnh gọi tới 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()))
1
unhammer
$ ulimit -a | grep pipe
pipe size            (512 bytes, -p) 8

Vì vậy, trên hộp Linux của tôi, tôi có các ống 8 * 512 = 4096 byte theo mặc định.

Solaris và nhiều hệ thống khác có chức năng ulimit tương tự.

0
Sam Watkins