PowerShell performans farkı filtresi ve işlev karşılaştırması


11

Şu anda Windows PowerShell 3.0 Adım Adım kitabını PowerShell hakkında daha fazla bilgi edinmek için okuyorum.

201 Sayfasında yazar, bir filtrenin işlevsel olarak aynı işlevden daha hızlı olduğunu gösterir.

Bu script bilgisayarında 2.6 saniye sürüyor:

MeasureAddOneFilter.ps1
Filter AddOne
{ 
 "add one filter"
  $_ + 1
}

Measure-Command { 1..50000 | addOne }

ve bu da 4.6 saniye

MeasureAddOneFunction.ps1
Function AddOne
{  
  "Add One Function"
  While ($input.moveNext())
   {
     $input.current + 1
   }
}

Measure-Command { 1..50000 | addOne }

Ben bu kodu çalıştırmak onun sonucunun tam tersini almak olduğunu:

.\MeasureAddOneFilter.ps1
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 226
Ticks             : 2266171
TotalDays         : 2,62288310185185E-06
TotalHours        : 6,29491944444444E-05
TotalMinutes      : 0,00377695166666667
TotalSeconds      : 0,2266171
TotalMilliseconds : 226,6171

.\MeasureAddOneFunction.ps1

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 93
Ticks             : 933649
TotalDays         : 1,08061226851852E-06
TotalHours        : 2,59346944444444E-05
TotalMinutes      : 0,00155608166666667
TotalSeconds      : 0,0933649
TotalMilliseconds : 93,3649

Birisi bana bunu açıklayabilir mi?

Yanıtlar:


13

Yazar daha fazla destekleyici kanıt sunmadıkça, belki sadece sıcak hava ile doluydu. Testi yaptın ve sonucu aldın ve yanlış olduğunu kanıtladın.

Düzenleme: Jeffrey Snover'ın blogundan:

Filtre, yalnızca bir işlem komut dosyası bloğu olan bir işlevdir

Bu tek başına, her ikisinin de aynı işlem bloklarına sahip olduğu göz önüne alındığında, bir filtrenin bir işleve göre bir hız avantajına sahip olacağına ikna etmek için yeterli değildir.

Ayrıca ne tür bir 1950 ekipmanı bir numaraya bir tane eklemek için 4.6 saniye sürüyor?

PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 7.7266


PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 0.4108

4.6 saniyedir. Belki de yazar, ikili dosyalar oluşturulmadan önce Powershell'in bir çeşit CTP sürümünü kullanıyordu. : P

Son olarak, testinizi yeni bir Powershell oturumunda, ancak ters sırada deneyin. Önce İşlevi, ikinci olarak Filtreyi deneyin veya tam tersi:

PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 6.597    


PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 0.4055

Görmek? İlk çalıştırdığınız zaman her zaman daha yavaş olacaktır. Bu, bir işleve veya filtreye bakılmaksızın ikinci işlemi daha hızlı hale getiren, belleğe zaten bir şeyler yüklemiş olmasıyla ilgili.

Yine de, kaç kez çalıştırıldığına bakılmaksızın, Fonksiyonun hala Filtre'den daha hızlı göründüğünü kabul edeceğim.

Measure-Command { Function AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 13.9813

Measure-Command { Filter AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 69.5301

Bu yüzden yazar yanılmıştı ... ve şimdi daha önce bir İşlev yerine bir Filtre kullanmamış olmaktan dolayı kendimi kötü hissetmiyorum.


4

Aslında her iki testte de aynı $ _ kullanırsanız fark çok daha küçük olur. Nedeni araştırmadım, ancak sanırım yazar her iki testte de aynı yaklaşımı kullanmıyor. Ayrıca, konsol çıktısı sonuçlara müdahale edebilir. Bu parçaları keserseniz, sayılar çok benzer. Görmek:

Function AddOneFunction
{  
    process {
        $_ + 1
    }
}

Filter AddOneFilter
{ 
    $_ + 1
}

write-host "First"
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds

write-host "Second"
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds

Komutların sırasını değiştirseniz bile sonuçlar çok yakın olacaktır.

First

TotalMilliseconds
-----------------
        84.6742
        84.7646
        89.8603
        82.3399
        83.8195
Second
        86.8978
        87.4064
        89.304
        94.4334
        87.0135

Belgeler ayrıca Filtrelerin temel olarak yalnızca işlem bloğuna sahip işlevlere kısayol olduğunu söylüyor. Bir işlem bloğu (veya $ input gibi otomatik değişkenleri kullanma gibi başka bir teknik) belirtmedikçe işlevler bir kez çalıştırılır, input kullanmaz ve ardışık düzende sonraki komuta geçmez.

Https://technet.microsoft.com/en-us/library/hh847829.aspx ve https://technet.microsoft.com/en-us/library/hh847781.aspx adresinde daha fazla bilgi bulabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.