पाइप और यहां स्ट्रिंग का उपयोग करके संसाधन का उपयोग


16

हम निम्नलिखित दो का उपयोग करके एक ही परिणाम प्राप्त कर सकते हैं bash,

echo 'foo' | cat

तथा

cat <<< 'foo'

मेरा प्रश्न यह है कि इन दोनों में क्या अंतर है जहाँ तक उपयोग किए गए संसाधनों का संबंध है और कौन सा बेहतर है?

मेरा विचार है कि पाइप का उपयोग करते समय हम एक अतिरिक्त प्रक्रिया echoऔर पाइप का उपयोग कर रहे हैं जबकि यहां स्ट्रिंग में केवल एक फाइल डिस्क्रिप्टर का उपयोग किया जा रहा है cat

जवाबों:


17

पाइप एक इन-कर्नेल फ़ाइल-सिस्टम में खोली गई फ़ाइल है और एक नियमित फ़ाइल ऑन-डिस्क के रूप में सुलभ नहीं है। यह स्वचालित रूप से केवल एक निश्चित आकार में बफर्ड होता है और अंततः पूर्ण होने पर ब्लॉक हो जाता है। ब्लॉक-डिवाइसेस पर खटास वाली फाइलों के विपरीत, पाइप चरित्र उपकरणों की तरह बहुत व्यवहार करते हैं, और इसलिए आमतौर पर समर्थन नहीं करते हैंlseek() और उनसे पढ़े गए डेटा को फिर से नहीं पढ़ा जा सकता है जैसा कि आप एक नियमित फ़ाइल के साथ कर सकते हैं।

यहां एक स्ट्रिंग एक नियमित फाइल है जो माउंटेड फाइल-सिस्टम में बनाई गई है। शेल फ़ाइल बनाता है और इसके एकमात्र फ़ाइल सिस्टम लिंक (और इसलिए इसे हटाने) को हटाने से पहले इसके डिस्क्रिप्टर को बनाए रखता है, इससे पहले कि वह फ़ाइल से / से एक बाइट लिखता / पढ़ता है। कर्नेल फ़ाइल के लिए आवश्यक स्थान बनाए रखेगा जब तक कि सभी प्रक्रियाएं इसके लिए सभी विवरणकों को जारी नहीं करती हैं। यदि इस तरह के डिस्क्रिप्टर से पढ़ने वाला बच्चा ऐसा करने की क्षमता रखता है, तो इसे lseek()दोबारा पढ़ा जा सकता है ।

दोनों मामलों में टोकन <<<और |फ़ाइल-डिस्क्रिप्टर का प्रतिनिधित्व करते हैं और जरूरी नहीं कि फाइलें खुद ही हों। आप इस बात का बेहतर अंदाजा लगा सकते हैं कि क्या कुछ इस तरह से किया जा रहा है:

readlink /dev/fd/1 | cat

... या ...

ls -l <<<'' /dev/fd/*

दो फाइलों के बीच सबसे महत्वपूर्ण अंतर यह है कि यहां स्ट्रिंग / डॉक बहुत ज्यादा एक बार में होने वाला मामला है - शेल बच्चे को रीड डिस्क्रिप्टर की पेशकश करने से पहले इसमें सभी डेटा लिखता है। दूसरी ओर, शेल उपयुक्त डिस्क्रिप्टर पर पाइप को खोलता है और बच्चों को पाइप के प्रबंधन के लिए कांटे देता है - और इसलिए इसे दोनों सिरों पर समवर्ती रूप से लिखा / पढ़ा जाता है।

ये भेद, हालांकि, केवल आम तौर पर सच हैं। जहां तक ​​मुझे पता है (जो वास्तव में अब तक नहीं है) यह बहुत ज्यादा हर शेल के बारे में सच है जो <<<यहाँ <<के एकल-अपवाद के साथ दस्तावेज़-पुनर्निर्देशन के लिए यहाँ स्ट्रिंग-शॉर्ट को संभालता है yashyash, busybox, dash, और अन्य ashवेरिएंट पाइप के साथ वापस करने के लिए यहां-दस्तावेज है, हालांकि, और उन के गोले में वहाँ वास्तव में सभी के बाद दोनों के बीच बहुत कम अंतर है करते हैं।

ठीक है - दो अपवाद। अब जब मैं इसके बारे में सोच रहा हूं, ksh93वास्तव में सभी के लिए एक पाइप नहीं करता है |, बल्कि पूरे व्यापार w / sockets को संभालता है - हालांकि यह एक डिलीट tmp फाइल करता है <<<*जैसा कि अन्य लोग करते हैं। क्या अधिक है, यह केवल पाइपलाइन के अलग-अलग खंडों को एक उप-परिवेश में रखता है जो एक प्रकार का पॉज़ीक व्यंजना है जो कम से कम यह एक उप- प्रकार की तरह कार्य करता है , और इसलिए कांटे भी नहीं करता है।

तथ्य यह है कि @ PSkocik का बेंचमार्क (जो बहुत उपयोगी है) यहाँ परिणाम कई कारणों से व्यापक रूप से भिन्न हो सकते हैं , और इनमें से अधिकांश कार्यान्वयन पर निर्भर हैं। यहाँ-दस्तावेज़ सेटअप के लिए सबसे बड़ा कारक लक्ष्य ${TMPDIR}फ़ाइल-सिस्टम प्रकार और वर्तमान कैश कॉन्फ़िगरेशन / उपलब्धता होगा, और फिर भी लिखे जाने वाले डेटा की मात्रा moreso होगी। पाइप के लिए यह स्वयं शेल प्रक्रिया का आकार होगा, क्योंकि आवश्यक कांटे के लिए प्रतियां बनाई जाती हैं। इस तरह से पाइपलाइन सेटअप bashमें भयानक है ( $(कमांड )प्रतिस्थापन शामिल करने के लिए ) - क्योंकि यह बड़ा और बहुत धीमा है, लेकिन इसके साथ ksh93शायद ही कोई फर्क पड़ता है।

यहाँ एक और छोटा खोल स्निपेट दिखाया गया है कि कैसे एक पाइप लाइन के लिए एक उप खोल को विभाजित करता है:

pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0

32059  #bash's pid
32059  #sh's ppid
32059  #1st subshell's $$
32111  #1st subshell sh's ppid
32059  #2cd subshell's $$
32114  #2cd subshell sh's ppid

एक पाइपलाइन्ड pipe_who()कॉल रिपोर्ट और वर्तमान शेल में एक रन की रिपोर्ट के बीच का अंतर एक (उपधारा के )निर्दिष्ट व्यवहार के कारण $$होता है जब यह विस्तारित होने पर मूल शेल के पीड का दावा करता है। हालांकि सब- bashडिले निश्चित रूप से अलग-अलग प्रक्रियाएं हैं, $$विशेष शेल पैरामीटर इस जानकारी का विश्वसनीय स्रोत नहीं है। फिर भी, उपधारा के बच्चे के shखोल इसकी रिपोर्ट करने के लिए सही नहीं है $PPID


बहुत मददगार। इन-कर्नेल फाइलसिस्टम, क्या इसका कोई नाम है? इसका मतलब यह है कि यह कर्नेल स्थान में मौजूद है?
utlamn

2
@utlamn - वास्तव में, हाँ - बस pipefs । यह सब कर्नेल है - लेकिन (सामान की तरह अलग से) इसलिए सभी फ़ाइल i / o है
mikeserv

10

बेंचमार्किंग का कोई विकल्प नहीं है:

pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do cat<<< foo >/dev/null; done  )

real    0m2.080s
user    0m0.738s
sys 0m1.439s
pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do echo foo |cat >/dev/null; done  )

real    0m4.432s
user    0m2.095s
sys 0m3.927s
$ time (for((i=0;i<1000;i++)); do cat <(echo foo) >/dev/null; done  )
real    0m3.380s
user    0m1.121s
sys 0m3.423s

और डेटा की एक बड़ी राशि के लिए:

TENMEG=$(ruby -e 'puts "A"*(10*1024*1024)')
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do echo "$TENMEG" |cat >/dev/null; done  )

real    0m42.327s
user    0m38.591s
sys 0m4.226s
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do cat<<< "$TENMEG" >/dev/null; done  )

real    1m26.946s
user    1m23.116s
sys 0m3.681s
pskocik@ProBook:~ 

$ time (for((i=0;i<100;i++)); do cat <(echo "$TENMEG") >/dev/null; done  )

real    0m43.910s
user    0m40.178s
sys 0m4.119s

यह प्रतीत होता है कि पाइप संस्करण की एक बड़ी सेटअप लागत है, लेकिन अंत में अधिक कुशल है।


@ माइकर्स यह सही था। मैंने बड़ी मात्रा में डेटा के साथ एक बेंचमार्क जोड़ा।
PSkocik

2
echo foo >/dev/shm/1;cat /dev/shm/1 >/dev/nullदोनों मामलों में तेज लग रहा था ...
user23013

@ user23013 यह समझ में आता है। मैं यह नहीं देखता कि दक्षता के लिए echo "$longstring"या तो <<<"$longstring"इसे छोटा किया जाएगा या छोटे तारों के साथ, दक्षता वैसे भी ज्यादा मायने नहीं रखती है।
PSkocik

यह दिलचस्प है कि मेरे मामले में (Ubuntu 14.04 पर, इंटेल क्वाड कोर i7) cat <(echo foo) >/dev/nullकी तुलना में तेज है echo foo | cat >/dev/null
पाबौक 12

1
@Prem हाँ, यह एक बेहतर तरीका होगा, लेकिन इससे भी बेहतर यह होगा कि आप इस बारे में बिल्कुल भी चिंता न करें और नौकरी के लिए सही टूल का इस्तेमाल करें। यह सोचने का कोई कारण नहीं है कि आनुवंशिकता प्रदर्शन-ट्यून होगी।
PSkocik
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.