පයිප්ප බෆරය කොතරම් විශාලද?


151

තුළ ප්රතිචාරයක් ලෙස | මම ඇයි ව්යාකුල කරනවා "සත්යය" එය makefile දී "|| සැබෑ" ලෙස එම බලපෑමක් ඇති කොට ඇත පරිශීලක cjm : ලියා

වළක්වා ගත හැකි තවත් හේතුවක් | trueනම්, විධානය මඟින් පයිප්ප බෆරය පිරවීම සඳහා ප්‍රමාණවත් ප්‍රතිදානයක් ලබා දෙන්නේ නම්, එය සත්‍ය ලෙස කියවීම බලා සිටීම අවහිර කරනු ඇත.

පයිප්ප බෆරයේ ප්‍රමාණය කුමක්දැයි සොයා ගැනීමට අපට ක්‍රමයක් තිබේද?

Answers:


150

පයිප්ප බෆරයක ධාරිතාව පද්ධති හරහා වෙනස් වේ (එකම පද්ධතියක පවා වෙනස් විය හැකිය). පයිප්පයක ධාරිතාවය සොයා බැලීමට ඉක්මන්, පහසු සහ හරස් වේදිකා ක්‍රමයක් ඇති බව මට විශ්වාස නැත.

උදාහරණයක් ලෙස මැක් ඕඑස් එක්ස් බයිට් 16384 ක ධාරිතාවක් පෙරනිමියෙන් භාවිතා කරයි, නමුත් පයිප්පයට විශාල ලිවීමක් කළහොත් බයිට් 65336 ධාරිතාවයට මාරු විය හැකිය, නැතහොත් දැනටමත් කර්නල් මතකය ඕනෑවට වඩා තිබේ නම් තනි පද්ධති පිටුවක ධාරිතාවයට මාරු වේ. පයිප්ප බෆර මගින් භාවිතා කරනු ලැබේ (බලන්න xnu/bsd/sys/pipe.h, සහ xnu/bsd/kern/sys_pipe.c; මේවා ෆ්‍රීබීඑස්ඩී වෙතින් වන බැවින්, එම හැසිරීම ද එහි සිදුවිය හැකිය).

එක් ලිනක්ස් පයිප්ප (7) මෑන් පිටුවක් පවසන්නේ ලිනක්ස් 2.6.11 සිට පයිප්ප ධාරිතාව බයිට් 65536 ක් වන අතර ඊට පෙර තනි පද්ධති පිටුවක් (උදා: (32-බිට්) x86 පද්ධති මත බයිට් 4096). කේතය ( include/linux/pipe_fs_i.h, සහ fs/pipe.c) පද්ධති පිටු 16 ක් භාවිතා කරන බව පෙනේ (එනම් 64 කිබී පද්ධති පිටුවක් 4 කිබී නම්), නමුත් එක් එක් පයිප්පයේ බෆරය පයිප්පයේ fcntl හරහා සකස් කළ හැකිය (උපරිම ධාරිතාව 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"

මැක් ඕඑස් එක්ස් 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

ලිනක්ස් 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සී ශීර්ෂ ලිපිගොනු වල අර්ථ දක්වා ඇති අගය (සහ සඳහා වන pathconf අගය _PC_PIPE_BUF), පයිප්පවල ධාරිතාව නියම නොකරයි, නමුත් පරමාණුකව ලිවිය හැකි උපරිම බයිට් ගණන ( POSIX write (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.  */

15
නියම පිළිතුර. විශේෂයෙන් POSIX ලිවීම (2) සඳහා වන සබැඳිය සඳහා, එය මෙසේ කියයි: නලයක size ලදායී ප්‍රමාණය හෝ FIFO (අවහිරයකින් තොරව එක් මෙහෙයුමක ලිවිය හැකි උපරිම මුදල) ​​ක්‍රියාත්මක කිරීම මත පදනම්ව ගතිකව වෙනස් විය හැකිය, එබැවින් එය කළ නොහැක ඒ සඳහා ස්ථාවර අගයක් නියම කිරීමට.
මයිකල්

5
fcntl()ලිනක්ස් ගැන සඳහන් කිරීම ගැන ස්තූතියි ; පරිශීලක අවකාශයේ බෆරින් වැඩසටහන් සෙවීම සඳහා මම ටික වේලාවක් ගත කර ඇති නිසා, ගොඩනඟන ලද පයිප්පවල ප්‍රමාණවත් තරම් බෆරයක් නොමැති බව මම සිතුවෙමි. මට CAP_SYS_RESOURCE තිබේ නම් හෝ මූල උපරිම නල ප්‍රමාණය පුළුල් කිරීමට කැමති නම් ඔවුන් එසේ කරන බව දැන් මට පෙනේ. මට අවශ්‍ය දේ ක්‍රියාත්මක වන්නේ නිශ්චිත ලිනක්ස් පරිගණකයක (මගේ) පමණක් බැවින් මෙය ගැටළුවක් නොවිය යුතුය.
ඩැනියෙල් එච්

1
කරුණාකර ඔබේ පිටපතෙහි මූලික අදහස පැහැදිලි කළ හැකිද? මම එය දෙස බලා සිටින අතර එය ක්‍රියාත්මක වන්නේ කෙසේදැයි මට සිතාගත නොහැකිද? VAR = $ ({}) මෙහි කැරලි වරහන් භාවිතා කිරීමේ අරමුණ කුමක්ද? ඔබට ස්තුතියි.
වකන් ටන්කා

Ak වකන් ටැංක: විවරණයක විස්තර කිරීම තරමක් වැඩි ය, නමුත් එම නිශ්චිත ඉදිකිරීම යනු විධාන ආදේශක ( ) හි ප්‍රතිදානයේ පරාමිති පැවරුමකි ( var=…) කාණ්ඩගත විධාන ( , සහ ) ඇතුළත් වේ . එය (අඩු පොදු) යළි-යොමුවීම් කිහිපයක් ද භාවිතා කරයි (එනම් සහ ). $(…){…}(…)0<&-3>&1
ක්‍රිස් ජොන්සන්

2
Ak වකන් ටැන්කා: පර්ල් වැඩසටහන එහි ප්‍රමාණයට (ෂෙල් වලින් සාදන ලද පයිප්පයක් - පරීක්ෂාවට ලක් කෙරෙන) යම් ප්‍රමාණයක කොටස් වලට ලියා එය ලියා ඇති ප්‍රමාණය (එහි දෝෂයක් ලැබෙන තුරු) - සාමාන්‍යයෙන් පයිප්පයේ බෆරය පිරී ඇති නිසා හෝ පයිප්පයේ කියවීමේ අවසානය කෙටි වේලාවකට පසු වසා දමා ඇති නිසා විය හැකිය ( exec 0<&-)). අවසාන වාර්තාව එකතු කරනු ලැබේ ( tail -1) සහ ලිවීමේ ප්‍රමාණය සමඟ මුද්‍රණය කෙරේ.
ක්‍රිස් ජොන්සන්

37

මෙම කවච රේඛාවට පයිප්ප බෆරයේ ප්‍රමාණයද පෙන්විය හැකිය:

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 භාවිතා කරන කෙටිම බාෂ්-වන්-ලයිනර්:

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

12
ඉතා කදිමයි! (dd if=/dev/zero bs=1 | sleep 999) &පසුව දෙවන බලා killall -SIGUSR1 ddදෙන 65536 bytes (66 kB) copied, 5.4987 s, 11.9 kB/s); - ඔබගේ විසඳුමක් ලෙස එම, නමුත් 1 බයිට යෝජනාවක්
frostschutz

2
වාර්තාව සඳහා, සොලාරිස් 10/11 SPARC / x86 ddහි 16 KiB හි විධාන වාරණ. ෆෙඩෝරා 23/25 x86-64 හි එය 64 කිබී හි අවහිර කරයි.
maxschlepzig

1
rofrostschutz: එය කදිම සරල කිරීමකි. ප්‍රායෝගිකව, ඔබට dd if=/dev/zero bs=1 | sleep 999පෙරබිමෙහි ධාවනය කළ හැකිය , තත්පරයක් රැඳී සිට පසුව ඔබන්න ^C. ඔබට ලිනක්ස් සහ බීඑස්ඩී / killalldd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
මැකෝස්

8

ෂෙල් විධාන පමණක් භාවිතා කරමින් සත්‍ය නල බෆර් ධාරිතාව ගවේෂණය කිරීම සඳහා තවත් විකල්ප කිහිපයක් මෙන්න:

# 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

Solaris 10, මත getconf PIPE_BUF /පිටපත් 5120ද ගැලපෙන ulimit -a | grep pipeප්රතිදානය නමුත් 16 KiB පසුව නොගැලපේ dd .. | sleep ...කුට්ටි.
maxschlepzig

ෆෙඩෝරා 25 හි, ඔබේ පළමු yesක්‍රමය මුද්‍රණය 73728කරන්නේ 64 dd if=/dev/zero bs=4096 status=none | pv -bn | sleep 1
කිබී

6

මෙය උබුන්ටු 12.04, වයිඑම්එම්වී හි ඉක්මන් හා අපිරිසිදු හැක් කිරීමකි

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

1

ඔබට පයිතන්> = 3.3 හි අගය අවශ්‍ය නම්, මෙන්න සරල ක්‍රමයක් (ඔබට ඇමතුමක් ලබා ගත හැකි යැයි උපකල්පනය කර 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()))

0
$ ulimit -a | grep pipe
pipe size            (512 bytes, -p) 8

ඉතින් මගේ ලිනක්ස් පෙට්ටියේ පෙරනිමියෙන් 8 * 512 = 4096 බයිට් පයිප්ප තිබේ.

සොලාරිස් සහ තවත් බොහෝ පද්ධති වලට සමාන ulimit ශ්‍රිතයක් ඇත.


2
මෙය (512 bytes, -p) 8ෆෙඩෝරා 23/25 සහ 512 bytes, -p) 10සොලාරිස් 10 හි මුද්‍රණය කරයි - එම අගයන් අත්හදා බැලීම් වලින් ලබාගත් අවහිර කිරීම් සමඟ නොගැලපේ dd.
maxschlepzig
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.