পরিবর্তনশীল সামগ্রী পড়ার চেয়ে ফাইল কেন দ্রুত খুলছে?


36

একটি bashস্ক্রিপ্ট আমি থেকে বিভিন্ন মান প্রয়োজন /proc/ফাইল। এখন অবধি আমার কাছে কয়েক ডজন লাইন ফাইলের মতো সরাসরি গ্রেপ করছে:

grep -oP '^MemFree: *\K[0-9]+' /proc/meminfo

আরও কার্যকর করার প্রয়াসে আমি ফাইলের সামগ্রীটি একটি ভেরিয়েবলে সংরক্ষণ করেছি এবং গ্রেপ করেছিলাম:

a=$(</proc/meminfo)
echo "$a" | grep -oP '^MemFree: *\K[0-9]+'

একাধিকবার ফাইলটি খোলার পরিবর্তে এটি একবার খোলার উচিত এবং পরিবর্তনশীল সামগ্রীটি গ্রেপ করা উচিত, যা আমি ধরে নিয়েছিলাম দ্রুততর হবে - তবে বাস্তবে এটি ধীর:

bash 4.4.19 $ time for i in {1..1000};do grep ^MemFree /proc/meminfo;done >/dev/null
real    0m0.803s
user    0m0.619s
sys     0m0.232s
bash 4.4.19 $ a=$(</proc/meminfo)
bash 4.4.19 $ time for i in {1..1000};do echo "$a"|grep ^MemFree; done >/dev/null
real    0m1.182s
user    0m1.425s
sys     0m0.506s

একই জন্য dashএবং zsh। আমি /proc/কারণ হিসাবে ফাইলগুলির বিশেষ অবস্থা সম্পর্কে সন্দেহ করেছি তবে আমি যখন /proc/meminfoএকটি নিয়মিত ফাইলে বিষয়বস্তু অনুলিপি করি এবং ফলাফলগুলি একই হয় তা ব্যবহার করি:

bash 4.4.19 $ cat </proc/meminfo >meminfo
bash 4.4.19 $ time for i in $(seq 1 1000);do grep ^MemFree meminfo; done >/dev/null
real    0m0.790s
user    0m0.608s
sys     0m0.227s

পাইপ সংরক্ষণের জন্য এখানে স্ট্রিং ব্যবহার করা এটি কিছুটা দ্রুততর করে তোলে তবে ফাইলগুলির সাথে তত দ্রুত নয়:

bash 4.4.19 $ time for i in $(seq 1 1000);do <<<"$a" grep ^MemFree; done >/dev/null
real    0m0.977s
user    0m0.758s
sys     0m0.268s

একটি ভেরিয়েবল থেকে একই বিষয়বস্তু পড়ার চেয়ে একটি ফাইল কেন দ্রুত খুলছে?


@ l0b0 এই অনুমানটি ত্রুটিযুক্ত নয়, প্রশ্নটি দেখায় যে আমি কীভাবে এটি নিয়ে এসেছি এবং উত্তরগুলি কেন এই ঘটনা তা ব্যাখ্যা করে। আপনার সম্পাদনা এখন শিরোনাম প্রশ্নের উত্তর দেয় না এমন উত্তরগুলি করে: তারা ঘটনাটি কিনা তা তারা বলে না।
মিষ্টি

ঠিক আছে, পরিষ্কার। কারণ শিরোনামটি বেশিরভাগ ক্ষেত্রেই ভুল ছিল, নির্দিষ্ট মেমরি ম্যাপ করা বিশেষ ফাইলগুলির জন্য নয়।
l0b0

@ l0b0 না, আমি এখানেই এটি জিজ্ঞাসা করছি: "আমি /proc/কারণ হিসাবে ফাইলগুলির বিশেষ অবস্থার বিষয়ে সন্দেহ করেছি , কিন্তু যখন আমি /proc/meminfoএকটি নিয়মিত ফাইলের বিষয়বস্তু অনুলিপি করি এবং ফলাফলগুলি একই হয়:" তবে এটি বিশেষ নয়/proc/ ফাইল, নিয়মিত ফাইল পড়া দ্রুত হয়!
মিষ্টি

উত্তর:


47

এখানে, এটি কোনও ভেরিয়েবলের বিষয়বস্তু পড়া বনাম কোনও ফাইল খোলার বিষয়ে নয় তবে অতিরিক্ত প্রক্রিয়াটি জালিয়াতি করা বা না করা সম্পর্কে আরও বেশি।

grep -oP '^MemFree: *\K[0-9]+' /proc/meminfoএমন একটি প্রক্রিয়া জাল করে যা কার্যকর করে grepযা খোলে /proc/meminfo(একটি ভার্চুয়াল ফাইল, মেমরিতে, কোনও ডিস্ক I / O জড়িত থাকে না) এটি পড়ে এবং রিজেক্সের সাথে মেলে।

এর মধ্যে সবচেয়ে ব্যয়বহুল অংশ হ'ল প্রক্রিয়াটি দৃking় করা এবং গ্রেপ ইউটিলিটি এবং এর লাইব্রেরি নির্ভরতা লোড করা, গতিশীল সংযোগ করা, লোকেল ডাটাবেস খুলুন, ডিস্কে থাকা কয়েক ডজন ফাইল (তবে সম্ভবত স্মৃতিতে ক্যাশেড)।

পড়ার অংশটি /proc/meminfoতুলনায় তুচ্ছ, কার্নেলটি সেখানে তথ্য তৈরি করতে grepখুব কম সময় প্রয়োজন এবং এটি পড়তে খুব কম সময় প্রয়োজন।

আপনি চালাতে পারেন strace -cযে, আপনি একটি দেখতে পাবেন open()এবং এক read()ব্যবস্থা কল পড়তেন /proc/meminfoঅন্য সব কিছুর সাথে তুলনা চীনাবাদাম হয় grepশুরু করার জন্য কাজ করে ( strace -cforking গণনা করা হয় না)।

ইন:

a=$(</proc/meminfo)

সেই $(<...)ksh অপারেটরকে সমর্থন করে এমন বেশিরভাগ শেলগুলিতে , শেলটি কেবল ফাইলটি খোলার জন্য এবং তার সামগ্রীগুলি পড়বে (এবং নতুন পংক্তির অক্ষরগুলি পিছনে ফেলে)। bashএটি ভিন্ন এবং অনেক কম দক্ষ যে এটি পড়ার জন্য কোনও প্রক্রিয়া জোর করে এবং একটি পাইপের মাধ্যমে পিতামাতার কাছে ডেটা প্রেরণ করে। তবে এখানে, এটি একবার হয়ে গেছে সুতরাং তাতে কোনও সমস্যা নেই।

ইন:

printf '%s\n' "$a" | grep '^MemFree'

শেলটির দুটি প্রক্রিয়া স্প্যান করা প্রয়োজন , যা একই সাথে চলমান তবে পাইপের মাধ্যমে একে অপরের মধ্যে ইন্টারঅ্যাক্ট করে। এই পাইপ তৈরি, ছিঁড়ে ফেলা এবং এখান থেকে লেখার এবং পড়ার কিছুটা ব্যয় হয়েছে। আরও বেশি ব্যয় হ'ল একটি অতিরিক্ত প্রক্রিয়া তৈরি করা। প্রক্রিয়াগুলির শিডিয়ুলিংয়ের পাশাপাশি কিছুটা প্রভাব রয়েছে।

আপনি দেখতে পাবেন যে zsh <<<অপারেটরটি ব্যবহার করা এটি কিছুটা দ্রুততর করে তোলে:

grep '^MemFree' <<< "$a"

জেডএস এবং বাশ-এ, এটি $aএকটি অস্থায়ী ফাইলের বিষয়বস্তু লেখার দ্বারা সম্পন্ন হয়েছে , এটি একটি অতিরিক্ত প্রক্রিয়া তৈরির চেয়ে কম ব্যয়বহুল, তবে সম্ভবত ডেটা সরাসরি পাওয়ার তুলনায় আপনাকে কোনও লাভ দেয় না /proc/meminfo। এটি আপনার পদ্ধতির চেয়ে কম দক্ষ যেটি /proc/meminfoডিস্কে অনুলিপি করে, যেহেতু প্রতিটি পুনরাবৃত্তিতে টেম্প ফাইলের লেখার কাজ করা হয়।

dashএখানে-স্ট্রিংগুলিকে সমর্থন করে না, তবে এর বংশগতিগুলি এমন একটি পাইপ প্রয়োগ করা হয়েছে যা কোনও অতিরিক্ত প্রক্রিয়া জড়িত না। ইন:

 grep '^MemFree' << EOF
 $a
 EOF

শেল একটি পাইপ তৈরি করে, একটি প্রক্রিয়া কাঁটাচামচ করে। শিশুটি grepতার স্টিডিনের সাথে পাইপের পড়ার শেষ হিসাবে চালায় এবং পিতামাতারা পাইপের অন্য প্রান্তে লিখিত সামগ্রীটি লেখেন।

তবে সেই পাইপ হ্যান্ডলিং এবং প্রক্রিয়া সিঙ্ক্রোনাইজেশনটি কেবলমাত্র ডেটা সরাসরি বন্ধ করার চেয়ে আরও ব্যয়বহুল হওয়ার সম্ভাবনা রয়েছে /proc/meminfo

এর সামগ্রীটি /proc/meminfoসংক্ষিপ্ত এবং উত্পাদন করতে খুব বেশি সময় নেয় না। আপনি যদি কিছু সিপিইউ চক্র সংরক্ষণ করতে চান তবে আপনি ব্যয়বহুল অংশগুলি মুছে ফেলতে চান: প্রক্রিয়াজাতকরণ এবং বাহ্যিক কমান্ডগুলি চালাচ্ছেন।

ভালো লেগেছে:

IFS= read -rd '' meminfo < /proc/meminfo
memfree=${meminfo#*MemFree:}
memfree=${memfree%%$'\n'*}
memfree=${memfree#"${memfree%%[! ]*}"}

bashযার প্যাটার্নের মিলটি খুব অকার্যকর হলেও এড়িয়ে চলুন । এর সাথে zsh -o extendedglob, আপনি এটি সংক্ষিপ্ত করতে পারেন:

memfree=${${"$(</proc/meminfo)"##*MemFree: #}%%$'\n'*}

নোটটি ^অনেকগুলি শেল (বিশেষত বর্ন, ফিশ, আরসি, এস এবং জেডএস কমপক্ষে এক্সটেন্ডডগ্লোব বিকল্পের সাথে) এর জন্য বিশেষ, আমি এটি উদ্ধৃত করার প্রস্তাব দিই। এছাড়াও নোট করুন যে echoস্বেচ্ছাসেবী তথ্য আউটপুট ব্যবহার করা যাবে না (তাই printfউপরের আমার ব্যবহার )।


4
আপনার ক্ষেত্রে printfশেলটি দুটি প্রক্রিয়া চালিত হওয়া দরকার, তবে printfশেলটি অন্তর্নির্মিত নয়?
ডেভিড কনরাড

6
@ ডেভিডকনরড এটি, তবে বেশিরভাগ শেলগুলি পাইপলাইনটি বর্তমান প্রক্রিয়ায় কোন অংশগুলির জন্য চালাতে পারে তা বিশ্লেষণ করার চেষ্টা করে না । এটি কেবল কাঁটাচামচ করে এবং বাচ্চাদের এটি বের করে দেয়। এই ক্ষেত্রে, পিতামাতার প্রক্রিয়া দু'বার কাঁটাচামচ করে; বাম পাশের শিশুটি তারপরে একটি অন্তর্নির্মিতটি দেখে এবং তা কার্যকর করে; ডান পাশের শিশুটি দেখে grepএবং চালায়।
চিপনার

1
@ ডেভিডকনরড, পাইপটি একটি আইপিসি প্রক্রিয়া, সুতরাং যে কোনও ক্ষেত্রে উভয় পক্ষকে বিভিন্ন প্রক্রিয়াতে চালাতে হবে। এটি থাকা অবস্থায় A | Bএটি অ্যান্ড টি কেএসএস বা জেডএস-এর মতো কয়েকটি শেল Bরয়েছে যা বর্তমান শেল প্রসেসে চালিত হয় যদি এটি বিল্টিন বা যৌগিক বা ফাংশন কমান্ড হয় তবে আমি বর্তমান প্রসেসে চালিত কোনওটিই জানি না A। যদি কিছু হয়, তা করার জন্য, তাদের একটি জটিল পদ্ধতিতে সিপাইপিকে পরিচালনা করতে হবে যেন Aশিশু প্রসেসে চলছে এবং শেলটি বন্ধ না করে আচরণের জন্য খুব আশ্চর্য হওয়ার কিছু নেই BBপিতামাতার প্রক্রিয়াটিতে চালানো এটি অনেক সহজ ।
স্টাফেন চেজেলাস

বাশ সমর্থন করে<<<
ডি বেন নোবল

1
@ ডি.বেনকনবিল, আমি বোঝাতে চাইছি না যে bashসমর্থন করা হয়নি <<<, ঠিক zshযেমন অপারেটর এসেছিল যেমন $(<...)Ksh থেকে এসেছে।
স্টাফেন চেজেলাস

6

আপনার প্রথম ক্ষেত্রে আপনি কেবল গ্রেপ ইউটিলিটি ব্যবহার করছেন এবং ফাইল থেকে কিছু সন্ধান করছেন /proc/meminfo, /procভার্চুয়াল ফাইল সিস্টেম তাই /proc/meminfoফাইল মেমরিতে থাকে এবং এর সামগ্রী আনতে এর জন্য খুব কম সময় প্রয়োজন।

তবে দ্বিতীয় ক্ষেত্রে, আপনি একটি পাইপ তৈরি করছেন, তারপরে প্রথম কমান্ডের আউটপুট এই পাইপটি ব্যবহার করে দ্বিতীয় কমান্ডের কাছে পাঠাচ্ছেন, যা ব্যয়বহুল।

পার্থক্যটি /proc(কারণ এটি স্মৃতিতে রয়েছে) এবং পাইপের কারণে, নীচের উদাহরণটি দেখুন:

time for i in {1..1000};do grep ^MemFree /proc/meminfo;done >/dev/null

real    0m0.914s
user    0m0.032s
sys     0m0.148s


cat /proc/meminfo > file
time for i in {1..1000};do grep ^MemFree file;done >/dev/null

real    0m0.938s
user    0m0.032s
sys     0m0.152s


time for i in {1..1000};do echo "$a"|grep ^MemFree; done >/dev/null

real    0m1.016s
user    0m0.040s
sys     0m0.232s

1

আপনি উভয় ক্ষেত্রেই একটি বহিরাগত কমান্ড কল করছেন (গ্রেপ)। বাহ্যিক কলটির জন্য একটি সাব-শেল প্রয়োজন। সেই শেলটি কাঁটাচাষ করা দেরির মূল কারণ। উভয় ক্ষেত্রে একই, একইভাবে: একই বিলম্ব।

আপনি যদি কেবলমাত্র একবার বাহ্যিক ফাইলটি পড়তে চান এবং এটি (একটি পরিবর্তনশীল থেকে) একাধিকবার ব্যবহার করতে চান তবে শেলের বাইরে যাবেন না:

meminfo=$(< /dev/meminfo)    
time for i in {1..1000};do 
    [[ $meminfo =~ MemFree:\ *([0-9]*)\ *.B ]] 
    printf '%s\n' "${BASH_REMATCH[1]}"
done

গ্রিপ কলটির জন্য পুরো 1 সেকেন্ডের পরিবর্তে কেবল 0.1 সেকেন্ড সময় নেয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.