আমি নিম্নলিখিত পরীক্ষাটি করেছি এবং আমার সিস্টেমে ফলস্বরূপ পার্থক্যটি দ্বিতীয় স্ক্রিপ্টের জন্য প্রায় 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