Фільтр різниці в продуктивності 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

Якщо автор не дав більше підтверджень, можливо, він просто сповнений гарячого повітря. Ви пройшли тест, отримали результат і довели його неправильно.

Редагувати: З блогу Джефрі Сновер:

Фільтр - це функція, що має просто блокування скриптів процесу

Це одне недостатньо для того, щоб переконати мене, що фільтр матиме перевагу у швидкості перед функцією, якщо обидва мають однакові технологічні блоки.

Також яке обладнання 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 секунди є ударом. Можливо, автор використовував якусь версію CTP Powershell до того, як бінарні файли будуть створені. : 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, які вже завантажували в пам'ять, це робить другу операцію швидшою, незалежно від того, чи це функція, чи фільтр.

Я визнаю, хоча функція все ще здається швидше, ніж фільтр, незалежно від того, скільки разів він працює.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.