Filter perbedaan kinerja PowerShell vs. fungsi

11

Saat ini saya membaca buku PowerShell 3.0 Langkah demi Langkah untuk mendapatkan wawasan lebih lanjut tentang PowerShell.

Pada halaman 201 penulis menunjukkan bahwa filter lebih cepat daripada fungsi dengan fungsi yang sama.

Script ini membutuhkan 2,6 detik di komputernya:

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

Measure-Command { 1..50000 | addOne }

dan ini 4,6 detik

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

Measure-Command { 1..50000 | addOne }

Jika saya menjalankan kode ini adalah kebalikan dari hasilnya:

.\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

Adakah yang bisa menjelaskan hal ini kepada saya?

Marcel Janus
sumber

Jawaban:

13

Kecuali jika penulis memberikan lebih banyak bukti pendukung, mungkin dia hanya penuh dengan udara panas. Anda telah menjalankan tes dan mendapatkan hasilnya serta membuktikan bahwa dia salah.

Sunting: Dari blog Jeffrey Snover:

Filter adalah fungsi yang hanya memiliki proses scriptblock

Itu saja tidak cukup untuk meyakinkan saya bahwa filter akan memiliki keunggulan kecepatan atas fungsi, mengingat keduanya memiliki blok proses yang identik.

Juga peralatan seperti apa tahun 1950-an yang dimiliki orang di tempat yang memerlukan waktu 4,6 detik untuk menambahkan satu ke nomor itu?

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 detik mendera. Mungkin penulis menggunakan semacam versi CTP dari Powershell sebelum binari-binari itu ngen'ed. : P

Terakhir, coba tes Anda dalam sesi Powershell baru, tetapi dalam urutan terbalik. Coba Fungsi pertama dan Filter kedua, atau sebaliknya:

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

Lihat? Yang pertama Anda jalankan akan selalu lebih lambat. Itu hanya tentang. NET internal karena sudah memuat barang ke memori yang membuat operasi kedua lebih cepat, terlepas dari apakah itu fungsi atau filter.

Saya akan mengakui bahwa Fungsi tersebut tampaknya secara konsisten lebih cepat daripada Filter, terlepas dari berapa kali dijalankan.

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

Jadi penulisnya salah ... dan sekarang saya merasa tidak enak karena tidak pernah menggunakan Filter alih-alih Fungsi sebelumnya.

Ryan Ries
sumber
4

Sebenarnya perbedaannya jauh lebih kecil jika Anda menggunakan $ _ yang sama di kedua tes. Saya tidak menyelidiki penyebabnya, tetapi saya kira itu karena penulis tidak menggunakan pendekatan yang sama di kedua tes. Juga, output konsol dapat mengganggu hasil. Jika Anda memotong bagian-bagian ini, angkanya sangat mirip. Lihat:

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

Hasilnya akan sangat dekat, bahkan jika Anda mengubah urutan perintah.

First

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

Dokumentasi juga mengatakan bahwa Filter pada dasarnya adalah jalan pintas ke fungsi dengan hanya blok proses. Fungsi, kecuali ditentukan dengan blok proses (atau teknik lain seperti menggunakan variabel otomatis seperti $ input), dijalankan sekali, jangan gunakan input dan jangan meneruskan ke perintah berikutnya dalam pipa.

Info lebih lanjut di https://technet.microsoft.com/en-us/library/hh847829.aspx dan https://technet.microsoft.com/en-us/library/hh847781.aspx

Vinicius Xavier
sumber