কোনও ফাইলকে মেমরিতে পড়ার চেয়ে দু'বার দ্রুত পুনরায় পুনরুক্তি করা এবং কম্পিউটিংয়ের দ্বিগুণ করা কেন?


26

আমি নিম্নলিখিত তুলনা করছি

tail -n 1000000 stdout.log | grep -c '"success": true'
tail -n 1000000 stdout.log | grep -c '"success": false'

নিম্নলিখিত সঙ্গে

log=$(tail -n 1000000 stdout.log)
echo "$log" | grep -c '"success": true'
echo "$log" | grep -c '"success": false'

এবং আশ্চর্যজনকভাবে দ্বিতীয়টি প্রথমটির চেয়ে প্রায় 3 গুণ বেশি সময় নেয়। এটি দ্রুত হওয়া উচিত, তাই না?


এটি দ্বিতীয় কারণ হতে পারে কারণ, ফাইলের সামগ্রীটি 3 বার এবং প্রথম উদাহরণে মাত্র দু'বার পড়া হয়?
লরেন্ট সি

4
কমপক্ষে দ্বিতীয় উদাহরণে আপনার স্ট্রিম $( command substitution )হয় না । বাকী সমস্ত পাইপগুলির মাধ্যমে একই সাথে ঘটে থাকে, তবে দ্বিতীয় উদাহরণে আপনাকে log=সম্পূর্ণ হওয়ার জন্য অপেক্ষা করতে হবে । << এখানে ব্যবহার করে দেখুন \ n $ {লগ = $ (কমান্ড)} \ n এখানে - আপনি কী পান তা দেখুন।
মাইক্রজারভ

অত্যন্ত বড় ফাইল, মেমরি বাধা মেশিন, বা আরও কিছু আইটেমের ক্ষেত্রে grepআপনি সম্ভবত কিছু স্পিডআপ ব্যবহার করতে দেখবেন teeযাতে ফাইলটি অবশ্যই একবার কেবল পঠিত হয়। cat stdout.log | tee >/dev/null >(grep -c 'true'>true.cnt) >(grep -c 'false'>false.cnt); cat true.cnt; cat false.cnt
ম্যাট

@ লরেন্টসি। না, এটি দ্বিতীয় উদাহরণে কেবল একবারে পড়ে। লেজের কাছে কেবল একটি কল আছে।
psusi

এখন এগুলি tail -n 10000 | fgrep -c '"success": true'এবং মিথ্যা সাথে তুলনা করুন ।
কোজিরো

উত্তর:


11

একদিকে, প্রথম পদ্ধতিটি tailদুটি বার কল করে, তাই এটি দ্বিতীয় পদ্ধতির চেয়ে আরও বেশি কাজ করতে হয় যা কেবল একবার এটি করে। অন্যদিকে, দ্বিতীয় পদ্ধতিতে শেলটিতে ডেটা অনুলিপি করতে হয় এবং তারপরে ব্যাক আউট করতে হয়, সুতরাং এটির প্রথম সংস্করণ যেখানে tailসরাসরি পাইপ করা হয়েছে তার চেয়ে বেশি কাজ করতে হবে grep। মাল্টি-প্রসেসর মেশিনে প্রথম পদ্ধতির অতিরিক্ত সুবিধা রয়েছে: এর grepসাথে সমান্তরালে কাজ করতে পারে tail, অন্যদিকে দ্বিতীয় পদ্ধতিটি কঠোরভাবে সিরিয়ালযুক্ত, প্রথমে tail, তারপরে grep

সুতরাং একজনের অপরটির চেয়ে দ্রুত হওয়া উচিত তার স্পষ্ট কারণ নেই।

কী চলছে তা যদি দেখতে চান তবে শেলটি কী সিস্টেম কল করে তা দেখুন। এছাড়াও বিভিন্ন শেল দিয়ে চেষ্টা করুন।

strace -t -f -o 1.strace sh -c '
  tail -n 1000000 stdout.log | grep "\"success\": true" | wc -l;
  tail -n 1000000 stdout.log | grep "\"success\": false" | wc -l'

strace -t -f -o 2-bash.strace bash -c '
  log=$(tail -n 1000000 stdout.log);
  echo "$log" | grep "\"success\": true" | wc -l;
  echo "$log" | grep "\"success\": true" | wc -l'

strace -t -f -o 2-zsh.strace zsh -c '
  log=$(tail -n 1000000 stdout.log);
  echo "$log" | grep "\"success\": true" | wc -l;
  echo "$log" | grep "\"success\": true" | wc -l'

পদ্ধতি 1 সহ, প্রধান স্তরগুলি হ'ল:

  1. tail এর প্রারম্ভিক বিন্দুটি পড়তে এবং এটির সন্ধান করতে
  2. tail4096-বাইট খণ্ডগুলি লিখেছেন যা grepতাদের উত্পাদনের সাথে সাথে তত দ্রুত পড়তে পারে।
  3. দ্বিতীয় অনুসন্ধানের স্ট্রিংয়ের জন্য আগের পদক্ষেপটি পুনরাবৃত্তি করুন।

পদ্ধতি 2 সহ, প্রধান স্তরগুলি হল:

  1. tail এর প্রারম্ভিক বিন্দুটি পড়তে এবং এটির সন্ধান করতে
  2. tail 4096-বাইট খণ্ড লিখেছেন যা বাশ একবারে 128 বাইট পড়ে, এবং zsh একবারে 4096 বাইট পড়ে।
  3. বাশ বা জেডএস 4096-বাইট খণ্ডগুলি লিখেছেন যা grepতাদের তৈরি হওয়ার সাথে সাথে তত দ্রুত পড়ে।
  4. দ্বিতীয় অনুসন্ধানের স্ট্রিংয়ের জন্য আগের পদক্ষেপটি পুনরাবৃত্তি করুন।

কমান্ড প্রতিস্থাপনের আউটপুট পড়ার সময় বাশের 128-বাইট খণ্ডগুলি তা উল্লেখযোগ্যভাবে হ্রাস করে; zsh আমার জন্য পদ্ধতি 1 হিসাবে দ্রুত হিসাবে আসে। আপনার মাইলেজ সিপিইউ টাইপ এবং সংখ্যা, সময়সূচী কনফিগারেশন, জড়িত সরঞ্জামগুলির সংস্করণ এবং ডেটার আকারের উপর নির্ভর করে পরিবর্তিত হতে পারে।


4k চিত্রের পৃষ্ঠা-আকার নির্ভর? আমি বলতে চাইছি, লেজ এবং zsh উভয়ই কেবল সাইক্যাকে ম্যাম্পিং করছে? (সম্ভবত এটি ভুল পরিভাষা, যদিও আমি আশা করি না ...) বাশ কী অন্যরকম করছে?
মাইক্রজারভ

এটি গিলসে স্পট! Zsh এর সাথে দ্বিতীয় পদ্ধতিটি আমার মেশিনে কিছুটা দ্রুত।
ফুনেহে

দুর্দান্ত কাজ গিলস, tks।
এক্স টিয়ান

@ মিমকিজার এই প্রোগ্রামগুলি কীভাবে আকার চয়ন করে তা দেখার জন্য আমি উত্সটির দিকে নজর দিইনি। 4096 দেখার সর্বাধিক কারণগুলি st_blksizeহ'ল একটি অন্তর্নির্মিত ধ্রুবক বা পাইপটির মূল্য, যা এই মেশিনে 4096 (এবং আমি জানি না কারণ এটি এমএমইউ পৃষ্ঠার আকার)। বাশের 128 টি একটি বিল্ট-ইন ধ্রুবক হতে হবে।
গিলস

@ গিলিস, চিন্তাশীল জবাবের জন্য ধন্যবাদ আমি ইদানীং পৃষ্ঠার আকারগুলি সম্পর্কে কৌতূহলী হয়েছি।
মাইকজারভের

26

আমি নিম্নলিখিত পরীক্ষাটি করেছি এবং আমার সিস্টেমে ফলস্বরূপ পার্থক্যটি দ্বিতীয় স্ক্রিপ্টের জন্য প্রায় 100 গুণ বেশি দীর্ঘ।

আমার ফাইলটি স্ট্রেস আউটপুট বলে bigfile

$ wc -l bigfile.log 
1617000 bigfile.log

স্ক্রিপ্ট

xtian@clafujiu:~/tmp$ cat p1.sh
tail -n 1000000 bigfile.log | grep '"success": true' | wc -l
tail -n 1000000 bigfile.log | grep '"success": false' | wc -l

xtian@clafujiu:~/tmp$ cat p2.sh
log=$(tail -n 1000000 bigfile.log)
echo "$log" | grep '"success": true' | wc -l
echo "$log" | grep '"success": true' | wc -l

গ্রেপের জন্য আসলে আমার কোনও মিল নেই তাই শেষ পাইপটিতে কিছুই লেখা হয়নি wc -l

সময়গুলি এখানে:

xtian@clafujiu:~/tmp$ time bash p1.sh
0
0

real    0m0.381s
user    0m0.248s
sys 0m0.280s
xtian@clafujiu:~/tmp$ time bash p2.sh
0
0

real    0m46.060s
user    0m43.903s
sys 0m2.176s

সুতরাং আমি দুটি স্ক্রিপ্ট আবার স্ট্রেস কমান্ডের মাধ্যমে চালিয়েছি

strace -cfo p1.strace bash p1.sh
strace -cfo p2.strace bash p2.sh

ট্রেসগুলি থেকে ফলাফলগুলি এখানে:

$ cat p1.strace 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.24    0.508109       63514         8         2 waitpid
  1.61    0.008388           0     84569           read
  1.08    0.005659           0     42448           write
  0.06    0.000328           0     21233           _llseek
  0.00    0.000024           0       204       146 stat64
  0.00    0.000017           0       137           fstat64
  0.00    0.000000           0       283       149 open
  0.00    0.000000           0       180         8 close
...
  0.00    0.000000           0       162           mmap2
  0.00    0.000000           0        29           getuid32
  0.00    0.000000           0        29           getgid32
  0.00    0.000000           0        29           geteuid32
  0.00    0.000000           0        29           getegid32
  0.00    0.000000           0         3         1 fcntl64
  0.00    0.000000           0         7           set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00    0.522525                149618       332 total

এবং p2.strace

$ cat p2.strace 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 75.27    1.336886      133689        10         3 waitpid
 13.36    0.237266          11     21231           write
  4.65    0.082527        1115        74           brk
  2.48    0.044000        7333         6           execve
  2.31    0.040998        5857         7           clone
  1.91    0.033965           0    705681           read
  0.02    0.000376           0     10619           _llseek
  0.00    0.000000           0       248       132 open
...
  0.00    0.000000           0       141           mmap2
  0.00    0.000000           0       176       126 stat64
  0.00    0.000000           0       118           fstat64
  0.00    0.000000           0        25           getuid32
  0.00    0.000000           0        25           getgid32
  0.00    0.000000           0        25           geteuid32
  0.00    0.000000           0        25           getegid32
  0.00    0.000000           0         3         1 fcntl64
  0.00    0.000000           0         6           set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00    1.776018                738827       293 total

বিশ্লেষণ

অবাক হওয়ার মতো বিষয় নয়, উভয় ক্ষেত্রেই প্রক্রিয়াটি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করে বেশিরভাগ সময় ব্যয় করা হয়, তবে পি 2 পি 1 এর চেয়ে 2.63 গুণ বেশি সময় অপেক্ষা করে এবং অন্যরা যেমন বলেছে, আপনি পি 2.শ দেরীতে শুরু করছেন।

সুতরাং এখন সম্পর্কে ভুলে যান waitpid, %কলামটি উপেক্ষা করুন এবং উভয় চিহ্নের সেকেন্ডের কলামটি দেখুন।

সবচেয়ে বড় সময় পি 1 তার বেশিরভাগ সময় সম্ভবত বোধগম্যভাবে পড়তে ব্যয় করে কারণ পঠন করার জন্য একটি বড় ফাইল রয়েছে, তবে পি 2 পি 1 এর চেয়ে 28.82 গুণ বেশি সময় ব্যয় করে। - bashএত বড় ফাইলটি ভেরিয়েবলের মধ্যে পড়ার প্রত্যাশা করে না এবং সম্ভবত একবারে বাফার পড়ছে, লাইনে বিভক্ত হয়ে অন্যটি পাবে।

পঠন গণনা পি 2 পি 1 এর জন্য 705 কে বনাম 84 কে, প্রতিটি পড়ার জন্য কার্নেল স্পেসে প্রসঙ্গের স্যুইচ প্রয়োজন হয় এবং আবার আউট হয়। পাঠের সংখ্যা এবং প্রসঙ্গে সুইচগুলির প্রায় 10 গুণ।

লেখার টাইম P2 41,93 বার আর ব্যয় P1 চেয়ে লেখ

লেখার গণনা পি 1 পি 2, 42 কে বনাম 21 কে-র চেয়ে বেশি লেখেন তবে সেগুলি আরও দ্রুত।

সম্ভবত লেজ লেখার বাফারের বিপরীতে echoলাইনগুলি তৈরি করার কারণে grep

আরও , পি 2 লিখিতভাবে বেশি সময় ব্যয় করে পড়ার চেয়ে বেশি , পি 1 এটি অন্যভাবে!

অন্যান্য ফ্যাক্টর সংখ্যা তাকান brkসিস্টেম কল: P2 2,42 বার বেশি এটা পড়া নেই ভঙ্গ ব্যয়! পি 1 এ (এটি নিবন্ধনও করে না)। brkযখন প্রোগ্রামটির ঠিকানা স্থানটি প্রসারিত করা দরকার কারণ প্রাথমিক পর্যায়ে যথেষ্ট পরিমাণ বরাদ্দ ছিল না, সম্ভবত বাশ সেই ফাইলটি ভেরিয়েবলের মধ্যে পড়তে হবে, এবং এটি এত বড় হওয়ার প্রত্যাশা না করার কারণে, এবং @ সাইক যেমন উল্লেখ করেছে, ফাইল খুব বড় হয়ে যায়, এমনকি এটি কাজ করে না।

tailসম্ভবত যথেষ্ট দক্ষ ফাইল রিডার, কারণ এটি এটির জন্যই তৈরি করা হয়েছিল, এটি সম্ভবত ফাইলটিকে স্মরণ করে এবং লাইন ব্রেকগুলির জন্য স্ক্যান করে, যাতে কার্নেলটি i / o অনুকূলিত করতে পারে। বাশ পড়া এবং লেখার জন্য সময় ব্যয় উভয়ই ভাল নয়।

p2 44ms এবং 41ms এ ব্যয় করে cloneএবং execvএটি পি 1 এর জন্য পরিমাপযোগ্য পরিমাণ নয়। সম্ভবত বাশ পড়া এবং লেজ থেকে পরিবর্তনশীল তৈরি করা।

অবশেষে টোটালস পি 1 পি 2 740 কে (4.93 গুণ বেশি) বনাম ~ 150k সিস্টেম কলগুলি কার্যকর করে।

ওয়েটপিড অপসারণ, p1 0.014416 সেকেন্ড ব্যয় করে সিস্টেম কলগুলি চালায়, পি 2 0.439132 সেকেন্ড (30 গুণ বেশি দীর্ঘ) longer

সুতরাং এটি প্রদর্শিত হয় যে পি 2 সিস্টেম স্পেস সম্পূর্ণ হওয়ার অপেক্ষায় এবং কার্নেলটি মেমরিটিকে পুনরায় সংগঠিত করতে ব্যতীত কিছু না করে ব্যয় করে ব্যয় করে, পি 1 আরও লেখালেখি সম্পাদন করে তবে আরও কার্যকর এবং এটি সিস্টেমের লোডকে তাত্পর্যপূর্ণ করে তোলে এবং তাই দ্রুত হয়।

উপসংহার

বাশ স্ক্রিপ্ট লেখার সময় আমি কখনই মেমোরি দিয়ে কোডিংয়ের বিষয়ে চিন্তা করার চেষ্টা করব না, এর অর্থ এই নয় যে আপনি দক্ষ হওয়ার চেষ্টা করবেন না।

tailএটি যা করে তা করার জন্য ডিজাইন করা হয়েছে, এটি সম্ভবত memory mapsফাইল যাতে এটি পড়ার পক্ষে দক্ষ এবং কার্নেলটিকে i / o অনুকূলিত করতে দেয়।

আপনার সমস্যাটিকে অনুকূল করার আরও ভাল উপায় হতে পারে প্রথমে grep"" সাফল্য ": 'লাইনগুলির জন্য এবং তারপরে ট্রুস এবং ফলসগুলি গণনা করতে পারে, grepএকটি গণনা বিকল্প রয়েছে যা আবার ট্রুগুলিকে গণনা wc -lকরে awkএবং লেজটি পাইপ করে এবং আরও ভাল স্থির করে pipe একই সাথে ফলস। p2 কেবল দীর্ঘ সময় নেয় না তবে ব্র্যাকগুলির সাথে মেমরিটি বদলে যাওয়ার সময় সিস্টেমটিতে লোড যুক্ত করে adds


2
টিএল; ডিআর: ম্যালোক (); যদি আপনি বলতে পারেন $ এটি কতটা বড় হওয়া দরকার তা লগ করতে এবং কোনও অপ্রয়োজনে ছাড়াই এটি একটি ওপিতে দ্রুত লিখতে পারতেন, এটি সম্ভবত তত দ্রুত হবে।
ক্রিস কে

5

আসলে প্রথম সমাধানটি ফাইলটিকে মেমরির মধ্যে পড়ে! একে ক্যাচিং বলা হয় এবং অপারেটিং সিস্টেম দ্বারা স্বয়ংক্রিয়ভাবে সম্পন্ন হয়।

এবং মাইক্রজার দ্বারা ইতিমধ্যে সঠিকভাবে ব্যাখ্যা করা হয়েছে ফাইলটি পড়ার grep সময় প্রথম সমাধানটি উপস্থিত থাকে যখন দ্বিতীয় সমাধানটি ফাইলটি পড়ার পরে এটি কার্যকর করে tail

সুতরাং বিভিন্ন সমাধানের কারণে প্রথম সমাধানটি দ্রুত। তবে এটি সর্বদা সত্য হতে হবে না। সত্যিই বড় ফাইলগুলির জন্য যা ওএস দ্বিতীয় সমাধানটি ক্যাশে না করার সিদ্ধান্ত নেয় দ্রুততর হতে পারে। তবে মনে রাখবেন যে আরও বড় ফাইলগুলির জন্য যা আপনার স্মৃতিতে ফিট করে না দ্বিতীয় সমাধানটি মোটেও কাজ করবে না।


3

আমি মনে করি মূল পার্থক্যটি খুব সহজভাবে echoধীর। এই বিবেচনা:

$ time (tail -n 1000000 foo | grep 'true' | wc -l; 
        tail -n 1000000 foo | grep 'false' | wc -l;)
666666
333333

real    0m0.999s
user    0m1.056s
sys     0m0.136s

$ time (log=$(tail -n 1000000 foo); echo "$log" | grep 'true' | wc -l; 
                                    echo "$log" | grep 'false' | wc -l)
666666
333333

real    0m4.132s
user    0m3.876s
sys     0m0.468s

$ time (tail -n 1000000 foo > bb;  grep 'true' bb | wc -l; 
                                   grep 'false' bb | wc -l)
666666
333333

real    0m0.568s
user    0m0.512s
sys     0m0.092s

আপনি উপরে দেখতে পারেন যে সময় সাশ্রয়ী পদক্ষেপটি ডেটা মুদ্রণ করছে। আপনি যদি কোনও নতুন ফাইলে পুনঃনির্দেশ করেন এবং এর মাধ্যমে গ্রেপ করেন তবে কেবল একবার ফাইলটি পড়লে এটি আরও দ্রুত হয়।


এবং অনুরোধ হিসাবে, এখানে একটি স্ট্রিং সহ:

 $ time (log=$(tail -n 1000000 foo); grep 'true' <<< $log | wc -l; 
                                     grep 'false' <<< $log | wc -l  )
1
1

real    0m7.574s
user    0m7.092s
sys     0m0.516s

এইটি আরও ধীর, সম্ভবতঃ কারণ এখানে স্ট্রিংটি সমস্ত লম্বা লাইনটিতে সমস্ত তথ্যকে একত্রিত করছে এবং এটি ধীর করে দেবে grep:

$ tail -n 1000000 foo | (time grep -c 'true')
666666

real    0m0.500s
user    0m0.472s
sys     0m0.000s

$ tail -n 1000000 foo | perl -pe 's/\n/ /' | (time grep -c 'true')
1

real    0m1.053s
user    0m0.048s
sys     0m0.068s

যদি ভেরিয়েবলটি উদ্ধৃত করা হয় যাতে কোনও বিভাজন না ঘটে, জিনিসগুলি একটু দ্রুত হয়:

 $ time (log=$(tail -n 1000000 foo); grep 'true' <<< "$log" | wc -l; 
                                     grep 'false' <<< "$log" | wc -l  )
666666
333333

real    0m6.545s
user    0m6.060s
sys     0m0.548s

তবে এখনও ধীর কারণ হার সীমাবদ্ধ পদক্ষেপটি ডেটা মুদ্রণ করছে।


আপনি কেন চেষ্টা করবেন না <<<এটি দেখতে কী আকর্ষণীয় হবে তা কোনও পার্থক্য করে কিনা।
গ্রিম

3

আমারও এই যেতে হয়েছিল ... প্রথমে, আমি ফাইলটি তৈরি করেছি:

printf '"success": "true"
        "success": "true"
        "success": "false"
        %.0b' `seq 1 500000` >|/tmp/log

আপনি নিজেকে উপরে চালানো, তাহলে আপনি 1.5million লাইনের আসা উচিত /tmp/log1 অনুপাত: 2 "success": "true"লাইনের "success": "false"লাইন।

পরের জিনিসটি আমি কিছু পরীক্ষা চালিয়েছিলাম। আমি একটি প্রক্সি মাধ্যমে সমস্ত পরীক্ষা চালিয়েছি shতাই timeশুধুমাত্র একটি একক প্রক্রিয়া দেখতে হবে - এবং তাই পুরো কাজের জন্য একটি একক ফলাফল প্রদর্শন করতে পারে।

এটি দ্বিতীয়তম ফাইল বর্ণনাকারী যুক্ত করা সত্ত্বেও এটি দ্রুততম বলে মনে হচ্ছে এবং tee,যদিও আমি মনে করি আমি ব্যাখ্যা করতে পারি কেন:

    time sh <<-\CMD
        . <<HD /dev/stdin | grep '"success": "true"' | wc -l
            tail -n 1000000 /tmp/log | { tee /dev/fd/3 |\
                grep '"success": "false"' |\
                    wc -l 1>&2 & } 3>&1 &
        HD
    CMD
666666
333334
sh <<<''  0.11s user 0.08s system 84% cpu 0.224 total

আপনার প্রথমটি এখানে:

    time sh <<\CMD
        tail -n 1000000 /tmp/log | grep '"success": "true"' | wc -l
        tail -n 1000000 /tmp/log | grep '"success": "false"' | wc -l
    CMD

666666
333334
sh <<<''  0.31s user 0.17s system 148% cpu 0.323 total

এবং আপনার দ্বিতীয়:

    time sh <<\CMD
        log=$(tail -n 1000000 /tmp/log)
        echo "$log" | grep '"success": "true"' | wc -l
        echo "$log" | grep '"success": "false"' | wc -l
    CMD
666666
333334
sh <<<''  2.12s user 0.46s system 108% cpu 2.381 total

আপনি দেখতে পাচ্ছেন যে আমার পরীক্ষায় আপনি যেমন ভেরিয়েবলটি পড়েছিলেন তখন গতিতে 3 * পার্থক্য বেশি ছিল।

আমি মনে করি এর অংশটি হ'ল শেল ভেরিয়েবলটি পড়ার সময় শেল দ্বারা বিভক্ত হয়ে পরিচালনা করতে হবে - এটি কোনও ফাইল নয়।

একজন here-documentঅন্য দিকে, সব ইন্টেন্টগুলি এবং উদ্দেশ্যের জন্য, একটি হল fileA -file descriptor, যাহাই হউক না কেন। এবং যেমনটি আমরা সবাই জানি - ইউনিক্স ফাইলগুলির সাথে কাজ করে।

আমার কাছে সবচেয়ে আকর্ষণীয় বিষয় here-docsহ'ল আপনি এগুলি -file-descriptors একটি সরল হিসাবে |pipe- এবং তাদের সম্পাদন করতে পারেন ip এটি খুব সুবিধাজনক কারণ এটি |pipeযেখানে আপনি চান সেখানে আপনাকে নির্দেশ করার ক্ষেত্রে আরও কিছুটা স্বাধীনতার সুযোগ দেয় ।

আমি বাধ্য ছিলাম কারণ প্রথম eats এবং সেখানে কিছু না সেকেন্ডের জন্য বাম পড়তে। তবে যেহেতু আমি এটিতে প্রবেশ করিয়েছি এবং এটিটি পাস করার জন্য এটি আবার বাছাই করে ততটা গুরুত্ব পেল না। আপনি অন্যদের পরামর্শ হিসাবে ব্যবহার করেন:teetailgrephere-doc |pipe|piped/dev/fd/3>&1 stdout,grep -c

    time sh <<-\CMD
        . <<HD /dev/stdin | grep -c '"success": "true"'
            tail -n 1000000 /tmp/log | { tee /dev/fd/3 |\
                grep -c '"success": "false"' 1>&2 & } 3>&1 &
        HD
    CMD
666666
333334
sh <<<''  0.07s user 0.04s system 62% cpu 0.175 total

এটি আরও দ্রুত।

কিন্তু আমি যখন এটিকে চালিত করি তখন এগুলিকে সম্পূর্ণ একযোগে চালানোর . sourcingজন্য heredocআমি প্রথম প্রক্রিয়াটিকে সাফল্যের সাথে ব্যাকগ্রাউন্ড করতে পারি না। এটি সম্পূর্ণরূপে ব্যাকগ্রাউন্ড ছাড়াই এখানে রয়েছে:

    time sh <<\CMD
        tail -n 1000000 /tmp/log | { tee /dev/fd/3 |\
            grep -c '"success": "true"' 1>&2 & } 3>&1 |\
                grep -c '"success": "false"'
    CMD
666666
333334
sh <<<''  0.10s user 0.08s system 109% cpu 0.165 total

তবে আমি যুক্ত করার সময় &:

    time sh <<\CMD
        tail -n 1000000 /tmp/log | { tee /dev/fd/3 |\
            grep -c '"success": "true"' 1>&2 & } 3>&1 & |\
                grep -c '"success": "false"'
    CMD
sh: line 2: syntax error near unexpected token `|'

তবুও, পার্থক্যটি আমার কাছে কমপক্ষে আমার জন্য কয়েক সেকেন্ডের কয়েকশত ভাগ বলে মনে হচ্ছে, তাই আপনি যা চাইবেন তেমন গ্রহণ করুন।

যাইহোক, এটির সাথে দ্রুত সঞ্চালনের teeকারণ হ'ল উভয়ই grepsএকই সময়ে tail. teeআমাদের জন্য ফাইলটির ডুপ্লিকেট অনুরোধ করে একই সাথে চালায় এবং এটিকে grepসমস্ত প্রবাহে দ্বিতীয় প্রসেসে বিভক্ত করে তোলে - সবকিছুই শুরু থেকে শেষ পর্যন্ত এক সাথে চালিত হয়, তাই তারা সমস্ত একই সময়ে প্রায় শেষ।

সুতরাং আপনার প্রথম উদাহরণে ফিরে যাওয়া:

    tail | grep | wc #wait til finished
    tail | grep | wc #now we're done

এবং আপনার দ্বিতীয়:

    var=$( tail ) ; #wait til finished
    echo | grep | wc #wait til finished
    echo | grep | wc #now we're done

তবে যখন আমরা আমাদের ইনপুট বিভক্ত করি এবং একই সাথে আমাদের প্রক্রিয়াগুলি চালিত করি:

          3>&1  | grep #now we're done
              /        
    tail | tee  #both process together
              \  
          >&1   | grep #now we're done

1
+1 তবে আপনার শেষ পরীক্ষাটি সিনট্যাক্স ত্রুটির সাথে মারা গেছে, আমি মনে করি না যে সময়গুলি ঠিক আছে এখানে :)
টেরডন

@terdon তারা ভুল হতে পারে - আমি ইঙ্গিত করছিলাম যে এটি মারা গেছে। আমি & এবং না এর মধ্যে পার্থক্য দেখিয়েছি - আপনি যখন এটি যুক্ত করেন, শেলটি খারাপ হয়ে যায়। তবে আমি প্রচুর অনুলিপি / পেস্ট করেছি তাই আমি হয়ত
দু'একটি জগাখিচুড়ি

sh: লাইন 2: অপ্রত্যাশিত টোকেনের নিকটে সিনট্যাক্স ত্রুটি `| '
টেরডন

@ এটারডন হ্যাঁ - "আমি সম্পূর্ণরূপে একযোগে চালানোর জন্য প্রথম প্রক্রিয়াটিকে সফলভাবে ব্যাকগ্রাউন্ড করতে পারি না See দেখুন?" প্রথমটি ব্যাকগ্রাউন্ডযুক্ত নয়, তবে আমি যখন যুক্ত করার চেষ্টা করি তখন "অপ্রত্যাশিত টোকেন"। যখন আমি . উত্স উত্স আমি & ব্যবহার করতে পারেন।
মাইকসার্ভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.