क्या डॉट-सोर्सिंग सिर्फ फाइल कंटेंट पढ़ने से धीमी है?


13

मैंने एक PowerShell मॉड्यूल लिखा है, जो विभिन्न स्रोत फ़ाइलों (यानी एक .ps1 फ़ाइल प्रति फ़ंक्शन) से फ़ंक्शन परिभाषाओं में खींचता है। यह हमें (एक टीम के रूप में) समानांतर में विभिन्न कार्यों पर काम करने की अनुमति देता है। मॉड्यूल (.psm1 फ़ाइल) उपलब्ध .ps1 फ़ाइलों की सूची प्राप्त करता है ...

$Functions = Get-ChildItem -Path $FunctionPath *.ps1

... फिर सूची के माध्यम से छोरों और डॉट-सोर्सिंग के माध्यम से प्रत्येक फ़ंक्शन परिभाषा में खींचता है:

foreach($Function in $Functions) {
  . $Function.Fullname                                     # Can be slow
}

समस्या: हमने देखा है कि जिस गति से यह पूरा होता है, वह लगभग 50 स्रोत फ़ाइलों के लिए 10 से 180 सेकंड तक भिन्न हो सकती है, यह इस बात पर निर्भर करता है कि हम किस मशीन पर परीक्षण करते हैं। हम समय में व्यापक भिन्नता की व्याख्या नहीं कर सकते हैं, और विश्वास करते हैं कि हमने मशीन प्रकार, OS, उपयोगकर्ता खाता, व्यवस्थापक अनुमतियाँ, PS प्रोफ़ाइल, PS संस्करण, आदि जैसे चर के लिए नियंत्रित किया है। एक ही मेजबान के लिए अलग-अलग समय लिया जा सकता है एक दिन से अगले करने के लिए उपयोगकर्ता।

हमें आश्चर्य हुआ कि क्या यह डिस्क एक्सेस की समस्या थी और परीक्षण किया कि हम डिस्क से कितनी जल्दी पढ़ सकते हैं। यह बताता है कि Get-Contentउन सभी फाइलों में तेजी से चल रहा था, जिनका हमने समस्या के समाधान में लाभ उठाया है:

foreach($Function in $Functions) {
  Invoke-Expression (Get-Content $Function.Fullname -Raw)  # Is quick
}

फाइल सामग्री को पढ़ने और निष्पादित करने की तुलना में डॉट-सोर्सिंग के माध्यम से इन कार्यों को इतना धीमा क्यों जोड़ा जा रहा है?

जवाबों:


17

विज्ञान की स्थापना

सबसे पहले, कुछ स्क्रिप्ट हमें यह परीक्षण करने में मदद करने के लिए। यह 2000 स्क्रिप्ट फ़ाइलों को उत्पन्न करता है, प्रत्येक एक छोटे से फ़ंक्शन के साथ:

1..2000 | % { "Function Test$_(`$someArg) { Return `$someArg * $_ }" > "test$_.ps1" }

सामान्य स्टार्टअप ओवरहेड को बहुत ज्यादा मायने नहीं रखने के लिए पर्याप्त होना चाहिए। आप चाहें तो और जोड़ सकते हैं। यह उन सभी को डॉट-सोर्सिंग का उपयोग करके लोड करता है:

dir test*.ps1 | % {. $_.FullName}

यह उनकी सामग्री को पहले पढ़कर उन सभी को लोड करता है:

dir test*.ps1 | % {iex (gc $_.FullName -Raw)}

अब हमें कुछ गंभीर निरीक्षण करने की आवश्यकता है कि पॉवरशेल कैसे काम करता है। मैं एक decompiler के लिए JetBrains dotPeek पसंद करता हूं । यदि आपने कभी .NET अनुप्रयोग में PowerShell को एम्बेड करने का प्रयास किया है , तो आप पाएंगे कि विधानसभा जिसमें अधिकांश प्रासंगिक सामान शामिल हैं System.Management.Automation। Decompile कि एक परियोजना और एक PDB में।

यह देखने के लिए कि यह सारा रहस्यमय समय कहाँ बिताया जा रहा है, हम एक प्रोफाइलर का उपयोग करेंगे। मैं विजुअल स्टूडियो में निर्मित एक को पसंद करता हूं। इसका उपयोग करना बहुत आसान हैप्रतीक स्थानों के लिए पीडीबी युक्त फ़ोल्डर जोड़ें । अब, हम एक PowerShell उदाहरण की प्रोफाइलिंग रनिंग कर सकते हैं जो कि केवल एक परीक्षण स्क्रिप्ट चलाता है। ( -Fileकोशिश करने के लिए पहली स्क्रिप्ट के पूर्ण पथ के साथ उपयोग करने के लिए कमांड-लाइन पैरामीटर सेट करें। छोटे स्क्रिप्ट वाले फ़ोल्डर में स्टार्टअप स्थान सेट करें। एक बार ऐसा हो जाने के बाद, powershell.exeलक्ष्य और परिवर्तन के तहत प्रविष्टि पर गुण खोलें। अन्य स्क्रिप्ट का उपयोग करने के लिए तर्क। फिर प्रदर्शन एक्सप्लोरर में सबसे ऊपरी आइटम पर राइट-क्लिक करें और प्रारंभ प्रोफ़ाइल चुनें। प्रोफाइलर दूसरी स्क्रिप्ट का उपयोग करके फिर से चलता है। अब हम तुलना कर सकते हैं। सुनिश्चित करें कि यदि आप विकल्प देते हैं तो "सभी कोड दिखाएं" पर क्लिक करें; मेरे लिए, जो नमूना रूपरेखा रिपोर्ट के सारांश दृश्य में सूचना क्षेत्र में दिखाई देता है।

नतीजे आते हैं

मेरी मशीन पर, Get-Content2000 स्क्रिप्ट फ़ाइलों के माध्यम से जाने के लिए संस्करण को 9 सेकंड का समय लगा। "हॉट पाथ" पर महत्वपूर्ण कार्य थे:

Microsoft.PowerShell.Commands.GetContentCommand.ProcessRecord
Microsoft.PowerShell.Commands.InvokeExpressionCommand.ProcessRecord

यह बहुत मायने रखता है: हमें Get-Contentडिस्क से सामग्री को पढ़ने के लिए इंतजार करना होगा, और हमें Invoke-Expressionउन सामग्रियों के उपयोग के लिए इंतजार करना होगा ।

डॉट-सोर्स संस्करण पर, मेरी मशीन ने उन फाइलों के माध्यम से काम करने के लिए 15 सेकंड से थोड़ा अधिक समय बिताया। इस बार, हॉट पाथ पर काम देशी तरीके थे:

WinVerifyTrust
CodeAuthzFullyQualifyFilename

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

इसका मतलब है

संक्षेप में, आप किसी तरह से सत्यापित की जाने वाली प्रत्येक फ़ाइल की प्रतीक्षा कर रहे हैं, संभवतः हस्ताक्षर के लिए जाँच की जाती है, भले ही यह आवश्यक नहीं है जब आप उन स्क्रिप्ट को प्रतिबंधित नहीं करते हैं जिन्हें चलाने की अनुमति है। जब आप gcऔर फिर iexसामग्री, यह ऐसा है जैसे आपने कंसोल पर फ़ंक्शन टाइप किया है, इसलिए सत्यापित करने के लिए कोई संसाधन नहीं है।


2
बेन, इस शानदार जवाब के लिए धन्यवाद। प्रभावित है कि आप डी-संकलन के रूप में दूर चले गए, जो कि मेरे द्वारा की गई कोशिश से परे एक कदम है। मैं देखूंगा कि क्या कोई तरीका है जिससे मैं उन मशीनों में से एक पर अपनी परीक्षण विधि का पालन कर सकता हूं जहां यह समस्या सबसे तीव्र है। यह एक लंबा समय लग सकता है ताकि आपकी सांस न चले!
चार्ली जॉयंट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.