ตัวกรองความแตกต่างของประสิทธิภาพ PowerShell กับฟังก์ชัน


11

ขณะนี้ฉันกำลังอ่านหนังสือ Windows PowerShell 3.0 ทีละขั้นตอนเพื่อรับข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับ PowerShell

ในหน้า 201 ผู้เขียนแสดงให้เห็นว่าตัวกรองนั้นเร็วกว่าฟังก์ชั่นที่ใช้งานได้

สคริปต์นี้ใช้เวลา 2.6 วินาทีในคอมพิวเตอร์ของเขา:

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

Measure-Command { 1..50000 | addOne }

และอันนี้ 4.6 วินาที

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

Measure-Command { 1..50000 | addOne }

หากฉันใช้รหัสนี้จะได้ผลลัพธ์ตรงข้ามกับเขาทุกประการ:

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

มีคนอธิบายเรื่องนี้กับฉันได้ไหม

คำตอบ:


13

นอกเสียจากว่าผู้เขียนจะให้หลักฐานสนับสนุนเพิ่มเติมบางทีเขาอาจเป็นแค่อากาศร้อน คุณทำการทดสอบและได้ผลลัพธ์และพิสูจน์ว่าเขาผิด

แก้ไข: จากบล็อกของ Jeffrey Snover:

ตัวกรองเป็นฟังก์ชันที่เพิ่งมีสคริปต์บล็อกกระบวนการ

เพียงอย่างเดียวนั้นไม่เพียงพอที่จะโน้มน้าวใจฉันว่าตัวกรองจะมีความได้เปรียบด้านความเร็วมากกว่าฟังก์ชั่นเนื่องจากทั้งคู่มีบล็อกกระบวนการที่เหมือนกัน

นอกจากนี้ยังมีอุปกรณ์ประเภทใดในปี 1950 ที่ใช้เวลา 4.6 วินาทีในการเพิ่มหนึ่งหมายเลข?

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 วินาทีคือการตี บางทีผู้เขียนอาจใช้ Powershell รุ่น CTP บางประเภทก่อนที่ไบนารีจะถูก ngen'ed : P

ในที่สุดลองทดสอบของคุณในเซสชัน Powershell ใหม่ แต่เรียงกลับกัน ลองใช้ฟังก์ชั่นก่อนและตัวกรองที่สองหรือในทางกลับกัน:

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

ดู? คนแรกที่คุณเรียกใช้จะช้ากว่าเสมอ มันเป็นเพียงแค่เกี่ยวกับ. NET internals ที่มีการโหลดเนื้อหาลงในหน่วยความจำแล้วซึ่งทำให้การทำงานที่สองเร็วขึ้นโดยไม่คำนึงว่าเป็นฟังก์ชั่นหรือตัวกรอง

ฉันจะยอมรับว่าฟังก์ชั่นยังคงดูเหมือนว่าจะเร็วกว่าตัวกรองอย่างต่อเนื่องไม่ว่ามันจะทำงานกี่ครั้งก็ตาม

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

ดังนั้นผู้เขียนจึงผิด ... และตอนนี้ฉันไม่รู้สึกแย่ที่ไม่เคยใช้ตัวกรองมาก่อนแทนที่จะใช้ฟังก์ชั่นมาก่อน


4

จริงๆแล้วความแตกต่างนั้นเล็กกว่ามากถ้าคุณใช้ $ _ ที่เหมือนกันในการทดสอบทั้งคู่ ฉันไม่ได้ตรวจสอบสาเหตุ แต่ฉันคิดว่าเป็นเพราะผู้เขียนไม่ได้ใช้วิธีการเดียวกันในการทดสอบทั้งสอง นอกจากนี้เอาต์พุตคอนโซลยังสามารถรบกวนผลลัพธ์ได้ หากคุณตัดส่วนเหล่านี้ตัวเลขจะคล้ายกันมาก ดู:

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

ผลลัพธ์จะใกล้เคียงกันแม้ว่าคุณจะเปลี่ยนลำดับของคำสั่ง

First

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

เอกสารประกอบยังกล่าวว่าตัวกรองนั้นเป็นทางลัดโดยทั่วไปสำหรับฟังก์ชั่นที่มีบล็อกกระบวนการเท่านั้น ฟังก์ชั่นยกเว้นว่ามีการระบุด้วยบล็อกกระบวนการ (หรือเทคนิคอื่น ๆ เช่นการใช้ตัวแปรอัตโนมัติเช่น $ input) เรียกใช้ครั้งเดียวอย่าใช้อินพุตและไม่ส่งผ่านไปยังคำสั่งถัดไปในไพพ์ไลน์

ข้อมูลเพิ่มเติมได้ที่https://technet.microsoft.com/en-us/library/hh847829.aspxและhttps://technet.microsoft.com/en-us/library/hh847781.aspx

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.