পাইপ বাফারটি কত বড়?


146

একটি মন্তব্য হিসাবে আমি বিভ্রান্ত হয়েছি কেন একটি মেকফাইলে "| সত্য" এর একই প্রভাব রয়েছে "|| সত্য" ব্যবহারকারী সিজেএম লিখেছেন:

এড়ানোর আরেকটি কারণ | সত্যটি হ'ল যদি কমান্ডটি পাইপ বাফারটি পূরণ করার জন্য পর্যাপ্ত আউটপুট তৈরি করে, এটি এটি পড়ার জন্য অপেক্ষা করতে অবরুদ্ধ করবে।

পাইপ বাফারটির আকার কী তা আমরা খুঁজে বের করার কিছু উপায় আছে?

উত্তর:


142

পাইপ বাফারের ক্ষমতা বিভিন্ন সিস্টেমে পরিবর্তিত হয় (এবং এমনকি এটি একই সিস্টেমেও পরিবর্তিত হতে পারে)। আমি নিশ্চিত নই যে পাইপের সক্ষমতা সন্ধানের জন্য দ্রুত, সহজ এবং ক্রস প্ল্যাটফর্মের উপায় আছে।

উদাহরণস্বরূপ, ম্যাক ওএস এক্স, ডিফল্টরূপে 16384 বাইটের ধারণক্ষমতা ব্যবহার করে, তবে পাইপটিতে বড় লেখালেখি করা গেলে 65336 বাইট ক্যাপাসিটিতে স্যুইচ করতে পারে, বা খুব বেশি কার্নেল মেমরি ইতিমধ্যে থাকলে একক সিস্টেমের পৃষ্ঠায় স্যুইচ করতে পারে পাইপ বাফার দ্বারা ব্যবহৃত হচ্ছে (দেখুন xnu/bsd/sys/pipe.hএবং xnu/bsd/kern/sys_pipe.cযেহেতু এগুলি ফ্রিবিএসডি থেকে আসে তাই সেখানেও একই আচরণ হতে পারে)।

একটি লিনাক্স পাইপ ()) ম্যান পৃষ্ঠাতে বলা হয়েছে যে পাইপ ক্ষমতাটি লিনাক্স ২. by.১১ এর পর থেকে 5৫৫36 since বাইট এবং এর আগে একটি একক সিস্টেমের পৃষ্ঠা (যেমন 4096 বাইট (32-বিট) x86 সিস্টেমে)। কোডটি ( include/linux/pipe_fs_i.hএবং fs/pipe.c) 16 টি পৃষ্ঠা পৃষ্ঠা ব্যবহার করছে বলে মনে হয় (যেমন কোনও সিস্টেম পৃষ্ঠা 4 কিবি হয় তবে 64 কিবি) তবে প্রতিটি পাইপের জন্য বাফারটি পাইপের উপর একটি 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সি হেডার ফাইলগুলিতে সংজ্ঞায়িত মান (এবং এর জন্য প্যাথকোনফ মান _PC_PIPE_BUF) পাইপগুলির সক্ষমতা নির্দিষ্ট করে না, তবে সর্বাধিক সংখ্যক বাইট যা পরমাণুভাবে রচনা করা যায় (দেখুন পসিক্স লিখন (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.  */

14
দুর্দান্ত উত্তর। বিশেষ করে পোসেক্স লিঙ্কের লিঙ্কের জন্য (২), যা বলেছে: একটি পাইপ বা ফিফোর কার্যকর আকার (একটি পরিমাণে ব্লকিং ব্যতীত আরও বেশি পরিমাণে লেখা যেতে পারে) প্রয়োগের উপর নির্ভর করে গতিশীলভাবে আলাদা হতে পারে, সুতরাং এটি সম্ভব নয় এটির জন্য একটি নির্দিষ্ট মান নির্দিষ্ট করতে।
মাইকেল

5
fcntl()লিনাক্সে উল্লেখ করার জন্য ধন্যবাদ ; আমি ইউজারস্পেস বাফারিং প্রোগ্রামগুলি সন্ধান করার জন্য কিছুটা সময় ব্যয় করেছি কারণ আমি ভেবেছিলাম অন্তর্নির্মিত পাইপগুলিতে যথেষ্ট পরিমাণে বাফার নেই। এখন আমি দেখতে পাচ্ছি যে তারা যদি আমার কাছে CAP_SYS_RESOURCE বা রুট থাকে তবে সর্বাধিক পাইপের আকার প্রসারিত করতে ইচ্ছুক। আমি যা চাই তা কেবল একটি নির্দিষ্ট লিনাক্স কম্পিউটারে চালিত হবে (খনি), এটি কোনও সমস্যা হওয়া উচিত নয়।
ড্যানিয়েল এইচ

1
আপনি কি দয়া করে আপনার স্ক্রিপ্টের প্রাথমিক ধারণাটি ব্যাখ্যা করতে পারেন? আমি এটির দিকে তাকিয়ে আছি এবং আমি কীভাবে এটি কাজ করে তা বুঝতে পারি না? বিশেষত এখানে VAR = $ ({}) কোঁকড়ানো বন্ধনী ব্যবহার করার উদ্দেশ্য কী? ধন্যবাদ.
ওয়াকান টানকা

@ ওয়াকানট্যাঙ্কা: একটি মন্তব্যে এটি বর্ণনা করা কিছুটা হলেও, সেই নির্দিষ্ট গঠনটি হ'ল একটি কমান্ড প্রতিস্থাপনের আউটপুট ( ) এর একটি প্যারামিটার অ্যাসাইনমেন্ট ( ) যা গ্রুপযুক্ত কমান্ড ( , এবং ) অন্তর্ভুক্ত করে। এটি বেশ কয়েকটি (কম সাধারণ) পুনর্নির্দেশগুলি (যেমন এবং ) ব্যবহার করে। var=…$(…){…}(…)0<&-3>&1
ক্রিস জনসন

2
@ ওয়াকানট্যাঙ্কা: পার্ল প্রোগ্রামটি একটি নির্দিষ্ট আকারের ব্লকগুলিতে তার স্টাডাউটকে (একটি শেল-তৈরি পাইপ - যা পরীক্ষা করা হচ্ছে) লিখেছে এবং তার স্টাডারের কাছে এটি কতটা লিখেছে তার চলমান মোট রিপোর্ট করে (যতক্ষণ না এটি ত্রুটি না পায়) পাইপটির বাফার পূর্ণরূপে বা সম্ভবত পাইপের পড়ার শেষটি অল্প সময়ের ( exec 0<&-)) পরে বন্ধ হয়ে গেছে বলে সাধারণত — চূড়ান্ত প্রতিবেদন সংগ্রহ করা হয় ( tail -1) এবং লেখার আকারের সাথে মুদ্রিত।
ক্রিস জনসেন

33

এই শেল লাইনটি পাইপ বাফার আকারটিও প্রদর্শন করতে পারে:

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

(বাফার পূর্ণ না হওয়া পর্যন্ত অবরুদ্ধ পাইপে 1 কে অংশ পাঠানো) ... কিছু পরীক্ষার ফলাফল:

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

প্রিন্টফ ব্যবহার করে সবচেয়ে ছোট বাশ-ও-লাইনার:

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

11
খুব সুন্দর! (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 কিবি কমান্ডটি ব্লক করে। ফেডোরা 23/25 x86-64 এ, এটি 64 কিবিতে অবরুদ্ধ হয়।
maxschlepzig

1
@ ফ্রসচুটজ: এটি একটি দুর্দান্ত সরলিকরণ। ব্যবহারিকভাবে, আপনি কেবল dd if=/dev/zero bs=1 | sleep 999অগ্রভাগে চলতে পারেন, এক সেকেন্ড অপেক্ষা করতে পারেন, তারপরে টিপুন ^C। আপনি যদি লিনাক্স এবং বিএসডি / ম্যাকোসের (ব্যবহারের চেয়ে বেশি শক্তিশালী killall) ওয়ান-লাইনার চেয়েছিলেন :dd if=/dev/zero bs=1 | sleep 999 & sleep 1 && pkill -INT -P $$ -x dd
এমকেমেন্ট 0

7

কেবল শেল কমান্ড ব্যবহার করে প্রকৃত পাইপ বাফার ক্ষমতাটি অনুসন্ধান করার জন্য এখানে আরও কিছু বিকল্প রয়েছে:

# 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

সোলারিস 10 এ, getconf PIPE_BUF /প্রিন্টগুলি 5120যা ulimit -a | grep pipeআউটপুটটির সাথে মেলে তবে 16 কিবি এর সাথে মেলে না যার পরে dd .. | sleep ...ব্লকগুলি।
maxschlepzig

ফেডোরা 25 তে, আপনার প্রথম yesপদ্ধতিটি 7372864 কিবি-র পরিবর্তে প্রিন্ট করে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

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

সুতরাং আমার লিনাক্স বাক্সে আমার কাছে ডিফল্টরূপে 8 * 512 = 4096 বাইট পাইপ রয়েছে।

সোলারিস এবং অন্যান্য অনেক সিস্টেমে একই রকম ইউলিমিট ফাংশন রয়েছে।


2
(512 bytes, -p) 8ফেডোরা 23/25 এবং 512 bytes, -p) 10সোলারিস 10 এ মুদ্রণগুলি - এবং সেই মানগুলি একটি ব্লকিংয়ের সাথে পরীক্ষামূলকভাবে প্রাপ্ত বাফার আকারগুলির সাথে মেলে না dd
maxschlepzig

0

পাইথন> = 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()))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.