किस दृष्टिकोण और एक प्रदर्शन की तुलना का उपयोग करने के मार्गदर्शन के साथ मदद करने के लिए मदद करने के लिए आकर्षक जवाब ।
एक पाइपलाइन के बाहर , उपयोग (PSv3 +):
$ वस्तुओं । नाम
जैसा कि rageandqq के उत्तर में प्रदर्शित किया गया है , जो कि वाक्य-रचना सरल और बहुत तेज है ।
एक पाइपलाइन में जहां परिणाम को आगे संसाधित किया जाना चाहिए या परिणाम स्मृति में एक पूरे के रूप में फिट नहीं होते हैं, उपयोग करें:
$ वस्तुओं | Select-Object -ExpandProperty नाम
- स्कॉट साद के उत्तर
-ExpandProperty
में इसकी आवश्यकता बताई गई है ।
- आपको एक-एक-एक प्रसंस्करण के सामान्य पाइपलाइन लाभ मिलते हैं, जो आम तौर पर तुरंत उत्पादन का उत्पादन करता है और मेमोरी उपयोग को स्थिर रखता है (जब तक कि आप अंततः परिणाम को किसी भी तरह इकट्ठा नहीं करते हैं)।
- ट्रेडऑफ़ :
- पाइपलाइन का उपयोग तुलनात्मक रूप से धीमा है ।
के लिए छोटे इनपुट संग्रह (सरणियों), तो आप शायद अंतर नोटिस नहीं , है, और, विशेष रूप से कमांड लाइन पर कभी-कभी आदेश टाइप करने के लिए सक्षम किया जा रहा आसानी से ज्यादा महत्वपूर्ण है।
यहां एक आसान-प्रकार का विकल्प है , जो हालांकि सबसे धीमा दृष्टिकोण है ; यह सरलीकृत ForEach-Object
वाक्यविन्यास का उपयोग करता है जिसे ऑपरेशन स्टेटमेंट (फिर, PSv3 +) कहा जाता है :; उदाहरण के लिए, निम्नलिखित PSv3 + समाधान मौजूदा कमांड में जोड़ना आसान है:
$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }
पूर्णता के लिए के लिए: अल्पज्ञात PSv4 + .ForEach()
सरणी विधि , अधिक comprehensivel में चर्चा इस लेख , है अभी तक एक और विकल्प :
# By property name (string):
$objects.ForEach('Name')
# By script block (more flexibility; like ForEach-Object)
$objects.ForEach({ $_.Name })
यह दृष्टिकोण एक ही ट्रेडऑफ़ के साथ सदस्य गणन के समान है, सिवाय इसके कि पाइपलाइन तर्क लागू नहीं होता है; यह थोड़ा धीमा है , हालांकि अभी भी पाइप लाइन की तुलना में अधिक तेज है।
नाम ( स्ट्रिंग तर्क) द्वारा एकल गुण मान निकालने के लिए , यह समाधान सदस्य गणना के साथ सममूल्य पर है (हालांकि बाद का वाक्य सरल है)।
स्क्रिप्ट ब्लॉक संस्करण , मनमाने ढंग से की अनुमति देता है परिवर्तनों ; यह एक तेज - ऑल-इन-मेमोरी-एट-एक बार - पाइपलाइन-आधारित ForEach-Object
cmdlet ( %
) का विकल्प है ।
विभिन्न दृष्टिकोणों के प्रदर्शन की तुलना करना
यहां विभिन्न दृष्टिकोणों के लिए नमूना समय दिया गया है, 10,000
वस्तुओं के एक इनपुट संग्रह के आधार पर , औसतन 10 रन; निरपेक्ष संख्याएँ महत्वपूर्ण नहीं हैं और कई कारकों के आधार पर अलग-अलग हैं, लेकिन यह आपको सापेक्ष प्रदर्शन का एहसास दिलाता है (एकल-कोर विंडोज़ 10 वीएम से आने वाला समय:
जरूरी
सापेक्ष प्रदर्शन इस बात के आधार पर भिन्न होता है कि क्या इनपुट ऑब्जेक्ट नियमित .NET प्रकार के उदाहरण हैं (उदाहरण के लिए, आउटपुट द्वारा Get-ChildItem
) या [pscustomobject]
उदाहरण (उदाहरण के लिए, आउटपुट द्वारा Convert-FromCsv
)।
इसका कारण यह है कि [pscustomobject]
गुणों को गतिशील रूप से PowerShell द्वारा प्रबंधित किया जाता है, और यह उन्हें (सांख्यिकीय रूप से परिभाषित) नियमित .NET प्रकार के नियमित गुणों की तुलना में अधिक तेज़ी से एक्सेस कर सकता है। दोनों परिदृश्य नीचे कवर किए गए हैं।
परीक्षण इनपुट के रूप में पहले से ही इन-मेमोरी-इन-फुल संग्रह का उपयोग करते हैं, ताकि शुद्ध संपत्ति निष्कर्षण प्रदर्शन पर ध्यान केंद्रित किया जा सके। इनपुट के रूप में एक स्ट्रीमिंग cmdlet / फ़ंक्शन कॉल के साथ, प्रदर्शन अंतर आम तौर पर बहुत कम स्पष्ट होंगे, क्योंकि उस कॉल के अंदर बिताया गया समय खर्च किए गए समय के बहुमत के लिए हो सकता है।
संक्षिप्तता के लिए, उपनाम %
का उपयोग ForEach-Object
cmdlet के लिए किया जाता है ।
सामान्य निष्कर्ष , दोनों नियमित .NET प्रकार और [pscustomobject]
इनपुट पर लागू होते हैं :
सदस्य-गणना ( $collection.Name
) और foreach ($obj in $collection)
समाधान सबसे तेज पाइपलाइन-आधारित समाधान की तुलना में 10 या उससे अधिक तेजी से सबसे तेज हैं।
हैरानी की बात है, की % Name
तुलना में बहुत खराब प्रदर्शन करता है % { $_.Name }
- इस GitHub मुद्दे को देखें ।
PowerShell Core यहां विंडोज पॉवर्सशेल को लगातार बेहतर बनाता है।
नियमित .NET प्रकार के साथ समय :
- PowerShell Core v7.0.0-पूर्वावलोकन .3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.005
1.06 foreach($o in $objects) { $o.Name } 0.005
6.25 $objects.ForEach('Name') 0.028
10.22 $objects.ForEach({ $_.Name }) 0.046
17.52 $objects | % { $_.Name } 0.079
30.97 $objects | Select-Object -ExpandProperty Name 0.140
32.76 $objects | % Name 0.148
- विंडोज पॉवरशेल v5.1.18362.145
Comparing property-value extraction methods with 10000 input objects, averaged over 10 runs...
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.012
1.32 foreach($o in $objects) { $o.Name } 0.015
9.07 $objects.ForEach({ $_.Name }) 0.105
10.30 $objects.ForEach('Name') 0.119
12.70 $objects | % { $_.Name } 0.147
27.04 $objects | % Name 0.312
29.70 $objects | Select-Object -ExpandProperty Name 0.343
निष्कर्ष:
- पावरशेल कोर में ,
.ForEach('Name')
स्पष्ट रूप से बेहतर प्रदर्शन .ForEach({ $_.Name })
। विंडोज पॉवरशेल में, उत्सुकता से, बाद में तेजी से होता है, यद्यपि केवल इतना ही।
[pscustomobject]
उदाहरणों के साथ समय :
- PowerShell Core v7.0.0-पूर्वावलोकन .3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.006
1.11 foreach($o in $objects) { $o.Name } 0.007
1.52 $objects.ForEach('Name') 0.009
6.11 $objects.ForEach({ $_.Name }) 0.038
9.47 $objects | Select-Object -ExpandProperty Name 0.058
10.29 $objects | % { $_.Name } 0.063
29.77 $objects | % Name 0.184
- विंडोज पॉवरशेल v5.1.18362.145
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.008
1.14 foreach($o in $objects) { $o.Name } 0.009
1.76 $objects.ForEach('Name') 0.015
10.36 $objects | Select-Object -ExpandProperty Name 0.085
11.18 $objects.ForEach({ $_.Name }) 0.092
16.79 $objects | % { $_.Name } 0.138
61.14 $objects | % Name 0.503
निष्कर्ष:
नोट के साथ कैसे [pscustomobject]
इनपुट .ForEach('Name')
दूर Outperforms द्वारा आधारित स्क्रिप्ट ब्लॉक संस्करण .ForEach({ $_.Name })
।
इसी तरह, [pscustomobject]
इनपुट Select-Object -ExpandProperty Name
विंडोज आधारित पावरशेल में लगभग पाईप पर आधारित पाइप लाइन को तेज बनाता है .ForEach({ $_.Name })
, लेकिन पावरशेल कोर में अभी भी लगभग 50% धीमा है।
संक्षेप में: के अजीब अपवाद के % Name
साथ, [pscustomobject]
गुणों को संदर्भित करने के स्ट्रिंग-आधारित तरीकों के साथ स्क्रिप्टब्लॉक-आधारित वाले को बेहतर बनाते हैं।
परीक्षणों के लिए स्रोत कोड :
ध्यान दें:
$count = 1e4 # max. input object count == 10,000
$runs = 10 # number of runs to average
# Note: Using [pscustomobject] instances rather than instances of
# regular .NET types changes the performance characteristics.
# Set this to $true to test with [pscustomobject] instances below.
$useCustomObjectInput = $false
# Create sample input objects.
if ($useCustomObjectInput) {
# Use [pscustomobject] instances.
$objects = 1..$count | % { [pscustomobject] @{ Name = "$foobar_$_"; Other1 = 1; Other2 = 2; Other3 = 3; Other4 = 4 } }
} else {
# Use instances of a regular .NET type.
# Note: The actual count of files and folders in your home dir. tree
# may be less than $count
$objects = Get-ChildItem -Recurse $HOME | Select-Object -First $count
}
Write-Host "Comparing property-value extraction methods with $($objects.Count) input objects, averaged over $runs runs..."
# An array of script blocks with the various approaches.
$approaches = { $objects | Select-Object -ExpandProperty Name },
{ $objects | % Name },
{ $objects | % { $_.Name } },
{ $objects.ForEach('Name') },
{ $objects.ForEach({ $_.Name }) },
{ $objects.Name },
{ foreach($o in $objects) { $o.Name } }
# Time the approaches and sort them by execution time (fastest first):
Time-Command $approaches -Count $runs | Select Factor, Command, Secs*
$results = @($objects | %{ $_.Name })
:। यह कई बार कमांड लाइन पर टाइप करने के लिए सुविधाजनक हो सकता है, हालांकि मुझे लगता है कि स्कॉट का जवाब आम तौर पर बेहतर है।