/ Dev / null एक फ़ाइल क्यों है? इसका कार्य एक साधारण कार्यक्रम के रूप में क्यों लागू नहीं किया गया है?


114

मैं लिनक्स पर विशेष फाइलों की अवधारणा को समझने की कोशिश कर रहा हूं। हालाँकि, एक विशेष फाइल होने में /devसादा मूर्खतापूर्ण लगता है, जब इसका कार्य मेरे ज्ञान में C की मुट्ठी भर लाइनों द्वारा कार्यान्वित किया जा सकता है।

इसके अलावा आप इसे बहुत ज्यादा उसी तरीके से उपयोग कर सकते हैं, यानी nullइसमें अनुप्रेषित करने के बजाय पाइपिंग /dev/null। क्या फ़ाइल के रूप में होने का कोई विशेष कारण है? क्या यह एक फ़ाइल नहीं बनाता है कई अन्य समस्याओं की वजह से एक ही फ़ाइल तक पहुंचने वाले कई प्रोग्राम जैसे?


20
संयोग से, इस ओवरहेड cat foo | barका अधिकांश हिस्सा भी बहुत खराब (पैमाने पर) क्यों है bar <foocatएक तुच्छ कार्यक्रम है, लेकिन यहां तक ​​कि एक तुच्छ कार्यक्रम लागत बनाता है (उनमें से कुछ FIFO शब्दार्थों के लिए विशिष्ट है - क्योंकि कार्यक्रम seek()FIFOs के अंदर नहीं हो सकते हैं , उदाहरण के लिए, एक ऐसा कार्यक्रम जिसे कुशलतापूर्वक लागू करने की मांग की जा सकती है, वह बहुत अधिक महंगा संचालन कर सकता है। जब एक पाइप लाइन दी जाती है, जैसे एक वर्ण डिवाइस के साथ, /dev/nullयह उन कार्यों को नकली कर सकता है, या एक वास्तविक फ़ाइल के साथ यह उन्हें लागू कर सकता है, लेकिन एक फीफो किसी भी तरह के संदर्भ-जागरूक हैंडलिंग की अनुमति नहीं देता है)।
चार्ल्स डफी

13
grep blablubb file.txt 2>/dev/null && dosomethingएक कार्यक्रम या एक समारोह होने के साथ अशक्त काम नहीं कर सका।
rexkogitans

16
आपको योजना 9 ऑपरेटिंग सिस्टम के बारे में पढ़ने के लिए यह ज्ञानवर्धक (या कम से कम दिमाग बढ़ाने वाला) लग सकता है, जहाँ यह देखने के लिए कि "सब कुछ एक फ़ाइल है" विज़न चल रहा था - फाइल के रूप में उपलब्ध संसाधनों की शक्ति को देखना थोड़ा आसान हो जाता है पथ एक बार जब आप एक प्रणाली को पूरी तरह से अवधारणा को गले लगाते हुए देखते हैं (अधिकतर / आंशिक रूप से, जैसे आधुनिक लिनक्स / यूनिक्स करते हैं)।
mtraceur

25
साथ ही कोई उनका कहना है के रूप में है कि एक डिवाइस ड्राइवर गिरी अंतरिक्ष में चल रहा है के साथ 'सी की तर्ज के एक मुट्ठी भर "एक कार्यक्रम , जवाब में से कोई भी अब तक वास्तव में" एक ही फ़ाइल तक पहुँचने भी कई कार्यक्रमों "के अनुमान को संबोधित किया सवाल में।
JdeBP

12
रे "अपने कार्य सी में लाइनों के एक मुट्ठी भर द्वारा कार्यान्वित किया जा सकता है": आप इस पर विश्वास नहीं होगा, लेकिन यह है सी में लाइनों के एक मुट्ठी भर द्वारा कार्यान्वित! उदाहरण के लिए, readफ़ंक्शन के शरीर में /dev/null"रिटर्न 0" शामिल होता है (जिसका अर्थ है कि यह कुछ भी नहीं करता है और, मुझे लगता है, एक ईओएफ में परिणाम): (स्थैतिक github.com/torvalds/linux/blob/master/ से) ड्राइवर / चार / मेम। ) ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }(ओह, मैं सिर्फ यह देखता हूं कि @JdeBP ने उस बिंदु को पहले से ही बना दिया है। वैसे भी, यहाँ चित्रण :-) है।
पीटर ए। श्नाइडर

जवाबों:


153

चरित्र-विशेष उपकरण का उपयोग करने के प्रदर्शन लाभ के अलावा, प्राथमिक लाभ प्रतिरूपकता है । / dev / null का उपयोग लगभग किसी भी संदर्भ में किया जा सकता है जहां एक फ़ाइल की अपेक्षा की जाती है, न कि केवल शेल पाइपलाइनों में। उन प्रोग्रामों पर विचार करें जो फाइलों को कमांड-लाइन मापदंडों के रूप में स्वीकार करते हैं।

# We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

ये सभी मामले हैं जहां एक कार्यक्रम को स्रोत या सिंक के रूप में उपयोग करना बेहद बोझिल होगा। यहां तक ​​कि शेल पाइपलाइन मामले में, स्टडआउट और स्टेडर को स्वतंत्र रूप से फाइलों में पुनर्निर्देशित किया जा सकता है, कुछ ऐसा जो निष्पादन के साथ सिंक के रूप में करना मुश्किल है:

# Suppress errors, but print output.
$ grep foo * 2>/dev/null

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

मुझे यकीन नहीं है कि मैं निष्पादन को कठिन बनाने के लिए अलग-अलग पुनर्निर्देशन के बारे में समझ रहा हूं। सी में, आप बस एक कर pipe, forkऔर execveकिसी अन्य प्रक्रिया पाइपिंग की तरह, बस में परिवर्तन के साथ dup2कॉल कि अप कनेक्शन, सही सेट? यह सच है सबसे गोले ऐसा करने के लिए सबसे सुंदर तरीके प्रदान करते हैं नहीं है, लेकिन शायद अगर हम इतना डिवाइस के रूप में फ़ाइल पैटर्न नहीं था और में चीजों का सबसे /devऔर /procनिष्पादनयोग्य के रूप में इलाज किया गया, गोले तरीके के साथ डिजाइन किया गया है | इसे आसानी से करने के लिए के रूप में हम अब पुनर्निर्देशित।
aschepler

6
@aschepler निष्पादक को सिंक करने के लिए पुनर्निर्देशित करना मुश्किल नहीं है। यह है कि उन अनुप्रयोगों को लिखना जो दोनों फ़ाइलों से लिख सकते हैं / पढ़ सकते हैं और नल सिंक एक फ़ाइल नहीं था, तो अधिक जटिल होगा। जब तक आप एक ऐसी दुनिया के बारे में बात कर रहे हैं जहाँ सब कुछ फ़ाइल होने के बजाय, सब कुछ एक निष्पादन योग्य है? यह एक बहुत अलग मॉडल होगा जो आपके पास * nix OS में है।
घन

1
@aschepler आप भूल गए wait4! आप सही हैं, पोसिक्स एपिस का उपयोग करके विभिन्न कार्यक्रमों के लिए स्टडआउट और स्टेडर को पाइप करना निश्चित रूप से संभव है, और अलग-अलग कमांडों के लिए स्टडआउट और स्टेडर को पुनर्निर्देशित करने के लिए एक चतुर शेल सिंटैक्स का आविष्कार करना संभव हो सकता है। हालाँकि, मुझे अभी ऐसे किसी भी शेल के बारे में पता नहीं है, और बड़ा मुद्दा यह है कि / dev / null बड़े करीने से मौजूदा टूलिंग (जो बड़े पैमाने पर फाइलों के साथ काम करता है) में फिट बैठता है, और बिन / null नहीं होगा। हम कुछ IO API की कल्पना भी कर सकते हैं जो किसी प्रोग्राम के लिए gcc (सिक्योरली!) आउटपुट के लिए आसान बनाता है, लेकिन हम जिस स्थिति में हैं, वह नहीं है।
ioctl

2
@ खोल के बारे में; दोनों zsh और bash कम से कम आपको ऐसा करने की अनुमति देंगे grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile), जिसके परिणामस्वरूप अलग से कार्रवाई की जाती है errfileऔरoutfile
Matija Nalis

62

निष्पक्षता में, यह प्रति फ़ाइल एक नियमित फ़ाइल नहीं है; यह एक चरित्र विशेष उपकरण है :

$ file /dev/null
/dev/null: character special (3/2)

यह एक फाइल या प्रोग्राम के बजाय एक डिवाइस के रूप में कार्य करता है, इसका मतलब है कि यह इनपुट या आउटपुट से पुनर्निर्देशित करने के लिए एक सरल ऑपरेशन है, क्योंकि इसे किसी भी फाइल डिस्क्रिप्टर से जोड़ा जा सकता है, जिसमें मानक इनपुट / आउटपुट / त्रुटि भी शामिल है।


24
cat file | nullओवरहेड का एक बहुत होगा, पहले एक पाइप स्थापित करने में, एक प्रक्रिया को स्पैनिंग, नई प्रक्रिया में "अशक्त" निष्पादित करना, आदि। इसके अलावा, nullस्वयं लूप रीडिंग बाइट्स में सीपीयू का एक बिट का उपयोग करता है जो बाद में बफर में होता है। बस छोड़ दिया ... /dev/nullकर्नेल में कार्यान्वयन इस तरह से अधिक कुशल है। इसके अलावा, क्या होगा यदि आप /dev/nullएक पुनर्निर्देशन के बजाय एक तर्क के रूप में पारित करना चाहते हैं ? (आप <(...)बैश में उपयोग कर सकते हैं , लेकिन यह भी भारी रास्ता है!)
filbranden

4
यदि आपको nullपुनर्निर्देशन का उपयोग करने के बजाय नामित प्रोग्राम पर पाइप करना है /dev/null, तो क्या शेल को प्रोग्राम को चलाने का एक सरल और स्पष्ट तरीका होगा, जबकि इसके स्टॉलर को शून्य भेजने के लिए?
मार्क प्लॉटनिक

5
ओवरहेड प्रदर्शन के लिए यह वास्तव में महंगा सेटअप है। मैं /dev/zeroइसके बजाय उपयोग करने का सुझाव दूंगा।
चिरलीस-स्ट्राइक-

20
वे उदाहरण गलत हैं। dd of=-एक फ़ाइल को लिखता है -, बस of=लिखने के लिए लिखने के लिए छोड़ दें क्योंकि यह ddडिफ़ॉल्ट रूप से लिखता है। पाइपिंग के falseरूप में काम करने के लिए falseअपनी ddस्टड नहीं पढ़ता है, इसलिए एक SIGPIPE के साथ मारा जाएगा। एक कमांड कि अपने इनपुट आप उपयोग कर सकते हैं छोड़ देता है के लिए ... cat > /dev/null। इसके अलावा तुलना जो शायद बोतल गर्दन के रूप में अप्रासंगिक हो सकती है, शायद यहां यादृच्छिक संख्या पीढ़ी होगी।
स्टीफन चेजलस

8
ddआदि के एएसटी संस्करण भी लिखने के लिए परेशान नहीं करते हैं जब वे गंतव्य का पता लगाते हैं / देव / अशक्त।
मार्क प्लॉटनिक

54

मुझे संदेह है कि यूनिक्स (और परिणामस्वरूप लिनक्स) को आकार देने वाले विज़न / डिज़ाइन के साथ बहुत कुछ क्यों है, और इससे होने वाले फायदे।

इसमें कोई संदेह नहीं है कि एक अतिरिक्त प्रक्रिया को कताई नहीं करने के लिए एक गैर-नगण्य प्रदर्शन लाभ है, लेकिन मुझे लगता है कि इसमें और भी बहुत कुछ है: प्रारंभिक यूनिक्स में एक "सब कुछ एक फ़ाइल है" रूपक है, जिसका यदि आप देखते हैं तो एक गैर-स्पष्ट लेकिन सुरुचिपूर्ण लाभ होता है। यह एक शेल स्क्रिप्टिंग परिप्रेक्ष्य के बजाय एक सिस्टम परिप्रेक्ष्य से है।

मान लें कि आपके पास अपना nullकमांड-लाइन प्रोग्राम और /dev/nullडिवाइस नोड है। शेल-स्क्रिप्टिंग के दृष्टिकोण से, यह foo | nullकार्यक्रम वास्तव में उपयोगी और सुविधाजनक है , और foo >/dev/nullटाइप करने के लिए थोड़ा अधिक समय लेता है और अजीब लग सकता है।

लेकिन यहाँ दो अभ्यास हैं:

  1. चलो nullमौजूदा यूनिक्स टूल और /dev/null- आसान: का उपयोग करके कार्यक्रम को लागू करें cat >/dev/null। किया हुआ।

  2. आप के /dev/nullसंदर्भ में लागू कर सकते हैं null?

आप पूरी तरह से सही हैं कि इनपुट को छोड़ने के लिए सी कोड तुच्छ है, इसलिए यह अभी तक स्पष्ट नहीं हो सकता है कि कार्य के लिए वर्चुअल फ़ाइल उपलब्ध होना उपयोगी क्यों है।

विचार करें: लगभग हर प्रोग्रामिंग भाषा को पहले से ही फाइलों, फ़ाइल डिस्क्रिप्टर और फ़ाइल रास्तों के साथ काम करने की आवश्यकता होती है, क्योंकि वे शुरुआत से यूनिक्स की "सब कुछ एक फाइल" प्रतिमान का हिस्सा थे।

यदि आपके पास ऐसे सभी प्रोग्राम हैं जो स्टैडआउट को लिखते हैं, तो ठीक है, प्रोग्राम को परवाह नहीं है यदि आप उन्हें एक वर्चुअल फ़ाइल में रीडायरेक्ट करते हैं जो सभी लिखता है, या प्रोग्राम में एक पाइप जो सभी लिखता है को निगल जाता है।

अब यदि आपके पास ऐसे प्रोग्राम हैं जो डेटा को पढ़ने या लिखने के लिए फ़ाइल पथ लेते हैं (जो कि अधिकांश प्रोग्राम करते हैं) - और आप उन प्रोग्रामों में "रिक्त इनपुट" या "इस आउटपुट को छोड़ दें" कार्यक्षमता को जोड़ना चाहते हैं - अच्छी तरह से, /dev/nullजो मुफ्त में आता है।

ध्यान दें कि इसका लालित्य यह है कि सभी शामिल कार्यक्रमों की कोड जटिलता को कम करता है - प्रत्येक सामान्य-लेकिन-विशेष usecase के लिए जो आपका सिस्टम एक वास्तविक "फ़ाइलनाम" के साथ "फ़ाइल" के रूप में प्रदान कर सकता है, आपका कोड कस्टम कमांड जोड़ने से बच सकता है -लाइन विकल्प और कस्टम कोड को संभालने के लिए पथ।

अच्छा सॉफ्टवेयर इंजीनियरिंग अक्सर किसी समस्या के कुछ तत्व को अमूर्त करने के लिए अच्छे या "प्राकृतिक" रूपकों को खोजने पर निर्भर करता है, जिनके बारे में सोचना आसान हो जाता है , लेकिन लचीला बना रहता है , ताकि आप मूल रूप से उच्च-स्तरीय समस्याओं को हल किए बिना ही हल कर सकें। लगातार निम्न-स्तरीय समस्याओं के समाधानों को लागू करने पर समय और मानसिक ऊर्जा खर्च करें।

"सब कुछ एक फ़ाइल है" संसाधनों तक पहुँचने के लिए ऐसा ही एक रूपक प्रतीत होता है: आप openएक दिए गए पथ को एक पदानुक्रमित नामस्थान में कॉल करते हैं, ऑब्जेक्ट के लिए एक संदर्भ (फ़ाइल डिस्क्रिप्टर) प्राप्त कर रहे हैं, और आप फ़ाइल डिस्क्रिप्टर पर readऔर writeआदि कर सकते हैं । आपके stdin / stdout / stderr भी फाइल डिस्क्रिप्टर हैं जो आपके लिए पहले से खोले गए हैं। आपके पाइप सिर्फ फाइलें और फाइल डिस्क्रिप्टर हैं, और फाइल पुनर्निर्देशन आपको इन सभी टुकड़ों को एक साथ गोंद करने देता है।

यूनिक्स उतने ही सफल हुए जितने हिस्से में इन अमूर्तियों के एक साथ काम करने के कारण हुआ, और /dev/nullउस पूरे हिस्से के रूप में सबसे अच्छी तरह से समझा जाता है।


PS यह "सब कुछ एक फ़ाइल है" के यूनिक्स संस्करण को देखने लायक है और इसके बाद के /dev/nullरूप में कई प्रणालियों में लागू किए गए रूपक के अधिक लचीले और शक्तिशाली सामान्यीकरण की दिशा में पहला कदम जैसे चीजें हैं ।

उदाहरण के लिए, यूनिक्स में विशेष फ़ाइल-जैसी ऑब्जेक्ट्स /dev/nullको कर्नेल में ही लागू किया जाना था, लेकिन यह पता चला है कि यह फ़ाइल / फ़ोल्डर फॉर्म में कार्यक्षमता को उजागर करने के लिए पर्याप्त उपयोगी है क्योंकि तब से कई सिस्टम बनाए गए हैं जो कार्यक्रमों के लिए एक रास्ता प्रदान करते हैं ऐसा करने के लिए।

सबसे पहले एक योजना 9 ऑपरेटिंग सिस्टम थी, जो उन्निक्स के कुछ लोगों द्वारा बनाई गई थी। बाद में, GNU हर्ड ने अपने "अनुवादकों" के साथ कुछ ऐसा ही किया। इस बीच, लिनक्स ने FUSE (जो अब तक अन्य मुख्यधारा प्रणालियों में फैल गया है) प्राप्त करना समाप्त कर दिया।


8
@PeterCordes जवाब की बात डिज़ाइन को न समझने की स्थिति से शुरू हो रही है। यदि हर कोई पहले से ही डिजाइन को समझ गया, तो यह प्रश्न मौजूद नहीं होगा।
ऑरेंजडॉग

1
@mtraceur: रूट अनुमति के बिना एक छवि फ़ाइल माउंट करें? कुछ सबूत दिखाते हैं कि FUSE को रूट की आवश्यकता नहीं हो सकती है, लेकिन मुझे यकीन नहीं है।
पीटर कॉर्डेस

1
@PeterCordes RE: "अजीब लगता है": यह डिज़ाइन के लिए माफी नहीं है, बस यह स्वीकार करना कि यह कैसे हो सकता है यदि आप इसके तहत सिस्टम कार्यान्वयन के बारे में नहीं सोच रहे हैं, और अभी तक सिस्टम के बारे में यूरेका पल नहीं आया है -विशिष्ट डिजाइन फायदे मैंने उस वाक्य को "शेल स्क्रिप्टिंग के नजरिए से" खोलकर स्पष्ट करने की कोशिश की, और इसके विपरीत कंट्रास्ट को जोड़ते हुए, सिस्टम के नजरिए से कुछ पहले के वाक्यों को देखा। आगे के विचार पर "अजीब लग सकता है" बेहतर है, इसलिए मैं इसे उसी पर लिखूंगा। मैं इसे और अधिक स्पष्ट किए बिना इसे स्पष्ट करने के लिए आगे के सुझावों का स्वागत करता हूं।
mtraceur

2
यूनिक्स के संबंध में एक युवा इंजीनियर के रूप में मुझे जो पहली बात बताई गई, वह थी "एवरीथिंग इज ए फाइल" और मुझे शपथ है कि आप राजधानियों को सुन सकते हैं। और उस विचार को जल्द पकड़ना यूनिक्स / लिनक्स को समझने में बहुत आसान लगता है। लिनक्स को उस डिज़ाइन दर्शन का अधिकांश भाग विरासत में मिला। मुझे खुशी है कि किसी ने इसका उल्लेख किया।
StephenG

2
@PeterCordes, DOS "हल" टाइपिंग की समस्या NULको हर निर्देशिका में मैजिक फाइलन के रूप में प्रदर्शित करता है, यानी आपको जो लिखना है, वह है > NUL
क्रिस्टियन सियुपिटु

15

मुझे लगता /dev/nullहै कि एक चरित्र उपकरण है (जो एक साधारण फ़ाइल की तरह व्यवहार करता है) प्रदर्शन कारणों से प्रोग्राम के बजाय ।

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

एक और धारणा: एक कार्यक्रम में प्रवेश करने के लिए प्राप्त कार्यक्रम द्वारा स्मृति को आवंटित करने की आवश्यकता होती है (भले ही इसे सीधे बाद में छोड़ दिया जाता है)। इसलिए यदि आप टूल में पाइप डालते हैं तो आपके पास डबल मेमोरी खपत है, एक बार भेजने के कार्यक्रम पर और फिर से प्राप्त होने वाले प्रोग्राम पर।


10
यह केवल सेटअप लागत नहीं है, यह है कि एक पाइप में प्रत्येक लिखने के लिए मेमोरी कॉपीिंग और रीडिंग प्रोग्राम के लिए एक संदर्भ स्विच की आवश्यकता होती है। (या पाइप बफर के भर जाने पर कम से कम एक संदर्भ स्विच। और पाठक को readडेटा कॉपी करते समय एक और कॉपी करना होगा )। यह एकल-कोर पीडीपी -11 पर नगण्य नहीं है जहां यूनिक्स डिजाइन किया गया था! मेमोरी बैंडविड्थ / कॉपी करना आज की तुलना में बहुत सस्ता है। writeएफडी पर खुली एक प्रणाली कॉल /dev/nullबफर से किसी भी डेटा को पढ़ने के बिना तुरंत वापस आ सकती है।
पीटर कॉर्डेस

@PeterCordes, मेरा नोट मूर्त है, लेकिन यह संभव है कि, विडंबना यह है कि, स्मृति आज पहले से कहीं अधिक महंगी लिखती है। एक 8-कोर सीपीयू संभावित रूप से एक घड़ी समय में 16 पूर्णांक ऑपरेशन करता है, जबकि एक एंड-टू-एंड मेमोरी राइट 16 घड़ियों (4GHz CPU, 250 MHz RAM) में पूरा होता है। यह 256 का कारक है। आधुनिक CPU में RAM RL02 से PDP-11 CPU की तरह है, लगभग एक परिधीय भंडारण इकाई की तरह! :) नहीं के रूप में सरल, स्वाभाविक रूप से, लेकिन कैश मार सब कुछ बाहर लिखा मिल जाएगा, और बेकार लिखते हैं कभी महत्वपूर्ण कैश स्थान के अन्य गणना से वंचित करेगा।
किमी किमी

@ किमी: हाँ, कर्नेल में पाइप बफर पर L3 कैश फुटप्रिंट के 2x 128kiB को बर्बाद nullकरना और प्रोग्राम में रीड बफर चूसना होगा, लेकिन अधिकांश मल्टी-कोर सीपीयू हर समय व्यस्त सभी कोर के साथ नहीं चलते हैं, इसलिए nullकार्यक्रम को चलाने के लिए सीपीयू समय ज्यादातर मुफ्त है। सभी खूंटे वाले एक सिस्टम पर, बेकार पाइपिंग एक बड़ी बात है। लेकिन नहीं, एक "हॉट" बफर को रैम में फ्लश किए बिना कई बार फिर से लिखा जा सकता है, इसलिए हम ज्यादातर केवल एल 3 बैंडविड्थ के लिए प्रतिस्पर्धा कर रहे हैं, कैश नहीं। महान नहीं, विशेष रूप से एक एसएमटी (हाइपरथ्रेडिंग) प्रणाली पर जहां एक ही भौतिक पर अन्य तार्किक कोर (एस) प्रतिस्पर्धा कर रहे हैं ...
पीटर कॉर्डेस

.... लेकिन आपकी स्मृति गणना बहुत त्रुटिपूर्ण है। आधुनिक सीपीयू में मेमोरी समांतरता बहुत होती है, इसलिए भले ही DRAM की विलंबता 200-400 कोर क्लॉक साइकिल और L3> 40 जैसी हो, बैंडविड्थ ~ 8 बाइट्स / घड़ी है। (आश्चर्यजनक रूप से, L3 या DRAM के लिए सिंगल-थ्रेडेड बैंडविड्थ क्वाड-चैनल मेमोरी बनाम क्वाड-कोर डेस्कटॉप के साथ कई-कोर Xeon पर बदतर है , क्योंकि यह अनुरोधों की अधिकतम संगामिति द्वारा सीमित है जो एक कोर उड़ान में रख सकता है। बैंडविड्थ) max_concurrency / विलंबता: एकल-थ्रेडेड मेमोरी थ्रूपुट के लिए ब्रॉडवेल -ई की तुलना में स्काइलेक इतना बेहतर क्यों है? )
पीटर कॉर्ड्स

... क्वाड-कोर बनाम 18-कोर की तुलना करने वाले हैसवेल नंबरों के लिए 7-cpu.com/cpu/Haswell.html भी देखें । वैसे भी, हाँ आधुनिक सीपीयू प्रति घड़ी काम का एक हास्यास्पद राशि प्राप्त कर सकते हैं, अगर वे स्मृति के लिए इंतजार नहीं कर रहे हैं। आपकी संख्या प्रति घड़ी केवल 2 ALU परिचालनों में दिखाई देती है, जैसे कि 1993 से पेंटियम, या आधुनिक कम-दोहरे दोहरे-ARM। एक Ryzen या Haswell संभावित रूप से 4 स्केलर पूर्णांक ALU ops + 2 मेमोरी ऑप्स प्रति कोर प्रति घड़ी या SIMD के साथ कहीं अधिक करता है। उदाहरण के लिए Skylake-AVX512 पर (प्रति कोर) 2-प्रति-घड़ी थ्रूपुट है vpaddd zmm: 16 32-बिट तत्व प्रति निर्देश।
पीटर कॉर्ड्स

7

इसके अलावा "सब कुछ एक फ़ाइल है" और इसलिए हर जगह उपयोग में आसानी है कि अधिकांश अन्य उत्तर पर आधारित हैं, @ @ 5626466 उल्लेख के रूप में प्रदर्शन समस्या भी है।

व्यवहार में दिखाने के लिए, हम साधारण प्रोग्राम बनाएंगे, जिसे nullread.c:

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

और इसके साथ संकलित करें gcc -O2 -Wall -W nullread.c -o nullread

(नोट: हम पाइप पर लेसेक (2) का उपयोग नहीं कर सकते हैं, इसलिए पाइप को हटाने का एकमात्र तरीका इससे पढ़ना है जब तक कि यह खाली न हो)।

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

मानक /dev/nullफ़ाइल पुनर्निर्देशन के साथ हम बहुत बेहतर गति प्राप्त करते हैं (वर्णित तथ्यों के कारण: कम संदर्भ स्विचिंग, कर्नेल इसे कॉपी करने के बजाय डेटा की अनदेखी करना):

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(यह वहाँ एक टिप्पणी होनी चाहिए, लेकिन उसके लिए बहुत बड़ा है और पूरी तरह से अपठनीय होगा)


आपने किस हार्डवेयर पर परीक्षण किया? 4.8GB / s 23GB / s की तुलना में काफी कम है जो मुझे Skylake i7-6700k (DDR4-2666) पर मिलता है, लेकिन बफर को L3 कैश में गर्म रहना चाहिए। इसलिए लागत का एक अच्छा हिस्सा सिस्टम कॉल स्पेक्टर के साथ महंगा है। + मेल्टडाउन शमन सक्षम। यह पाइपिंग के लिए दोगुना दर्द होता है, क्योंकि पाइप बफ़र 1M से छोटे होते हैं, इसलिए यह सिस्टम लिखने / पढ़ने के लिए अधिक है। लगभग 10x पूर्ण अंतर मेरी अपेक्षा से भी बदतर है, हालांकि, मेरे स्काइलेक सिस्टम पर 23GB / s बनाम है। 3.3GB / s , x86-64 लिनक्स 4.15.8-1-ARCH चल रहा है, इसलिए यह 6.8 का कारक है। वाह, सिस्टम कॉल अब महंगे हैं)
पीटर कॉर्डेस

1
64k पाइप बफ़र्स के साथ @PeterCordes 3GB / s प्रति सेकंड 2x 103124 syscalls का सुझाव देता है ... और संदर्भ स्विच की संख्या, हे। एक सर्वर सीपीयू पर, 200000 syscalls प्रति सेकंड के साथ, आप पीटीआई से ~ 8% ओवरहेड की उम्मीद कर सकते हैं, क्योंकि बहुत कम काम सेट है। (मैं जिस ग्राफ का संदर्भ दे रहा हूं उसमें पीसीआईडी ​​ऑप्टिमाइज़ेशन शामिल नहीं है, लेकिन शायद यह छोटे कामकाजी सेटों के लिए इतना महत्वपूर्ण नहीं है)। इसलिए मुझे यकीन नहीं है कि पीटीआई का वहां बड़ा प्रभाव है? brendangregg.com/blog/2018-02-09/…
sourcejedi

1
ओह दिलचस्प है, इसलिए यह 2MB L2 कैश के साथ एक सिल्वरमोंट है , इसलिए आपके ddबफर + प्राप्त बफर फिट नहीं होते हैं; आप शायद अंतिम-स्तरीय कैश बैंडविड्थ के बजाय मेमोरी बैंडविड्थ के साथ काम कर रहे हैं। आपको 512k बफ़र्स या 64k बफ़र्स के साथ बेहतर बैंडविड्थ मिल सकती है। ( straceमेरे डेस्कटॉप के अनुसार , writeऔर read1048576 वापस आ रहे हैं, इसलिए मुझे लगता है कि इसका मतलब है कि हम केवल उपयोगकर्ता का भुगतान कर रहे हैं <-> टीएलबी अमान्य + शाखा-भविष्यवाणी की कर्नेल लागत एक बार MiB के अनुसार, 64k @sourcejuni के अनुसार नहीं है। यह स्पेक्टर है। शमन कि लागत सबसे अधिक है, मुझे लगता है)
पीटर कॉर्ड्स

1
@sourcejedi: स्पेक्टर शमन सक्षम syscallहोने के साथ ENOSYSही, उस रिटर्न की लागत सही है ~ स्काइलेक पर स्पेक्टर शमन सक्षमता के साथ ~ 1800 चक्र, इसमें से अधिकांश बीपीयू कोwrmsr अमान्य करता है, जो @ बेयोनोप के परीक्षण के अनुसार है । शमन अक्षम के साथ, उपयोगकर्ता-> कर्नेल-> उपयोगकर्ता दौर यात्रा का समय ~ 160 चक्र है। लेकिन अगर आप बहुत सारी मेमोरी को छू रहे हैं , तो मेल्टडाउन शमन भी महत्वपूर्ण है। Hugepages को मदद करनी चाहिए (कम TLB प्रविष्टियों को पुनः लोड करने की आवश्यकता है)।
पीटर कॉर्डेस

1
@PeterCordes एक एकल-कोर यूनिक्स प्रणाली पर, हम निश्चित रूप से प्रति 64K पर 1 संदर्भ स्विच देखेंगे, या जो कुछ भी आपके पाइप बफर था, और जो चोट लगी होगी ... वास्तव में मैं 2 सीपीयू कोर के साथ संदर्भ स्विच की समान संख्या भी देखता हूं] ( unix.stackexchange.com/questions/439260/… ); यह एक संदर्भ स्विच (नाममात्र "निष्क्रिय प्रक्रिया") के रूप में प्रत्येक 64k के लिए नींद / जागने के चक्र को भी गिनना चाहिए। एक ही सीपीयू पर पाइपलाइन प्रक्रियाओं को रखना वास्तव में तेजी से दोगुना से अधिक काम करता है।
sourcejedi

6

आपका प्रश्न यह है कि अगर किसी फाइल के बदले में अशक्त कार्यक्रम का उपयोग करके सादगी में कुछ प्राप्त किया जाएगा, तो यह प्रश्न है। शायद हम "जादू फ़ाइलों" की धारणा से छुटकारा पा सकते हैं और इसके बजाय सिर्फ "साधारण पाइप" हैं।

लेकिन विचार करें, एक पाइप भी एक फ़ाइल है । वे सामान्य रूप से नामित नहीं हैं, और इसलिए केवल उनके फ़ाइल विवरणकों के माध्यम से हेरफेर किया जा सकता है।

इस कुछ उदाहरण उदाहरण पर विचार करें:

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

बैश की प्रक्रिया प्रतिस्थापन का उपयोग करके हम एक ही चीज़ को अधिक गोल चक्कर के माध्यम से पूरा कर सकते हैं:

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

के grepलिए बदलें echoऔर हम कवर के नीचे देख सकते हैं:

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

<(...)निर्माण सिर्फ एक फ़ाइल नाम के साथ बदल दिया जाता है, और ग्रेप सोचता है कि यह किसी भी पुराने फ़ाइल खोलने, यह सिर्फ नाम से होता है /dev/fd/63। यहाँ, /dev/fdएक जादू निर्देशिका है जो फ़ाइल तक पहुँचने वाले प्रत्येक फ़ाइल विवरणक के लिए नामांकित पाइप बनाती है।

हम इसे एक साधारण mkfifoपाइप की तरह दिखाते हुए नामांकित पाइप बनाने के लिए कम जादू कर सकते हैं ls:

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

अन्य:

$ echo -e 'foo\nbar\nbaz' > foofifo

और निहारना, grep उत्पादन होगा foo

मुझे लगता है कि एक बार जब आप पाइप और नियमित फाइलों को महसूस करते हैं और विशेष फाइलें जैसे / dev / null सभी बस फाइलें हैं, तो यह स्पष्ट है कि एक अशक्त कार्यक्रम को लागू करना अधिक जटिल है। कर्नेल को किसी फ़ाइल को लिखने के लिए किसी भी तरह से संभालना पड़ता है, लेकिन / dev / null के मामले में यह केवल फर्श पर लिखता है, जबकि एक पाइप के साथ इसे वास्तव में बाइट्स को किसी अन्य प्रोग्राम में स्थानांतरित करना पड़ता है, जो तब होता है वास्तव में उन्हें पढ़ा।


@ लेल हाँ? फिर इको प्रिंट क्यों होता है /dev/fd/63?
फिल फ्रॉस्ट

हम्म। अच्छी बात। खैर, यह गोले द्वारा कार्यान्वित किया जाता है, इसलिए शायद आपका खोल पुराने बॉर्न शेल से अलग है जिसे मैं बड़ा हुआ था।
लाईल

एक अंतर यह है कि गूँज करने से इको स्टड से नहीं पढ़ता है, लेकिन मैं यह नहीं सोच सकता कि शेल को कैसे पता चलेगा कि इससे पहले कि वे उन्हें मारते हैं।
लाइल

1
और स्ट्रेस यह स्पष्ट करता है: मेरे लिए। आपके पास यह बिल्कुल सही है, बैश के साथ। '<(...)' निर्माण <फ़ाइल नाम से कुछ अलग कर रहा है। हम्म। मैंने कुछ सीखा।
लाइल

0

मैं तर्क दूंगा कि ऐतिहासिक प्रतिमानों और प्रदर्शन से परे एक सुरक्षा मुद्दा है। विशेषाधिकार प्राप्त निष्पादन क्रेडेंशियल्स के साथ कार्यक्रमों की संख्या को सीमित करना, चाहे कितना सरल हो, सिस्टम सुरक्षा का एक मूलभूत सिद्धांत है। /dev/nullसिस्टम सेवाओं द्वारा उपयोग के कारण ऐसे प्रतिस्थापन के लिए निश्चित रूप से प्रतिस्थापन की आवश्यकता होगी। आधुनिक सुरक्षा ढांचे कारनामों को रोकने के लिए एक उत्कृष्ट काम करते हैं, लेकिन वे मूर्ख नहीं हैं। फ़ाइल के रूप में एक्सेस किया गया कर्नेल संचालित डिवाइस का शोषण करना अधिक कठिन है।


यह बकवास लगता है। बग-मुक्त कर्नेल ड्राइवर लिखना बग-रहित प्रोग्राम लिखने से आसान नहीं है जो इसके स्टड को + पढ़ता है। यह setuid या कुछ भी होने के लिए तो दोनों के लिए की जरूरत नहीं है /dev/nullया एक प्रस्तावित इनपुट को त्यागकर कार्यक्रम, हमले वेक्टर ही होगा: एक स्क्रिप्ट या प्रोग्राम है जो रूट के रूप में चलाता है कुछ अजीब करने के लिए मिलता है (करने की कोशिश की तरह lseekमें /dev/nullया खुले यह एक ही प्रक्रिया से कई बार, या IDK क्या है। या /bin/nullएक अजीब वातावरण के साथ आह्वान , या जो भी)।
पीटर कॉर्ड्स

0

जैसा कि अन्य ने पहले ही बताया है, /dev/null यह एक प्रोग्राम है जो कोड की एक मुट्ठी भर लाइनों से बना है। यह सिर्फ इतना है कि कोड की ये लाइनें कर्नेल का हिस्सा हैं।

इसे स्पष्ट करने के लिए, यहाँ लिनक्स कार्यान्वयन है: एक वर्ण डिवाइस रीड या लिखे जाने पर फ़ंक्शन को कॉल करता है। /dev/nullकॉल करने के लिए लिखना write_null , जबकि कॉल read_null पढ़ रहा है , यहाँ पंजीकृत है

वस्तुतः कोड की एक मुट्ठी भर लाइनें: ये कार्य कुछ नहीं करते हैं। यदि आपको पढ़ने और लिखने के अलावा अन्य कार्यों को गिनना है तो आपको हाथों पर उंगलियों से कोड की अधिक लाइनों की आवश्यकता होगी।


शायद मुझे इसे और अधिक सटीक रूप से लिखना चाहिए। मेरा मतलब था कि एक कार्यक्रम के बजाय एक चार डिवाइस के रूप में इसे क्यों लागू किया जाए। यह कुछ रास्ता होगा, लेकिन कार्यक्रम कार्यान्वयन निश्चित रूप से सरल होगा। जैसा कि अन्य जवाबों में बताया गया है, इसके कुछ लाभ हैं; उनके बीच दक्षता और सुवाह्यता प्रमुख है।
अंकुर एस

ज़रूर। मैंने यह जवाब सिर्फ इसलिए जोड़ा क्योंकि वास्तविक कार्यान्वयन मज़ेदार था (मैंने इसे हाल ही में स्वयं खोजा था), लेकिन असली कारण यह है कि दूसरों ने वास्तव में बताया।
Matthieu Moy

मैं भी! मैंने हाल ही में लिनक्स में डिवाइस सीखना शुरू किया और जवाब काफी जानकारीपूर्ण थे
अंकुर एस

-2

मुझे आशा है कि आप / देव / चारजन / देव / शून्य और उनके जैसे अन्य लोगों से भी अवगत होंगे / देव / अशक्त।

LINUX / UNIX के पास इनमें से कुछ उपलब्ध हैं - ताकि लोग WELL WRITTEN CODE FrAGMEnTS का अच्छा उपयोग कर सकें।

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

शून्य को एक मौजूदा फ़ाइल को पॉप्युलेट करने के लिए बनाया गया है या पूरी तरह से शून्य का उत्पादन करता है

/ dev / null दिमाग में एक ही विचार के साथ सिर्फ एक और उपकरण है।

आपके टूलकिट के इन सभी साधनों का मतलब है कि आपके पास एक मौजूदा कार्यक्रम बनाने का आधा मौका है, डिवाइस या फ़ाइल प्रतिस्थापन के रूप में उनकी (आपकी विशिष्ट आवश्यकता) की परवाह किए बिना कुछ अनूठा करें।

चलो यह देखने के लिए एक प्रतियोगिता की स्थापना करते हैं कि लिनेक्स के आपके संस्करण में केवल कुछ ही चरित्र उपकरणों को दिए गए सबसे रोमांचक परिणाम का उत्पादन कौन कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.