В настоящее время я читаю книгу Windows PowerShell 3.0 Step by Step, чтобы получить больше информации о 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
Может кто-то объяснить это мне?
Если автор не представил дополнительных подтверждающих доказательств, возможно, он был просто полон горячего воздуха. Вы провели тест, получили результат и доказали, что он неправ.
Изменить: из блога Джеффри Сновера:
Фильтр - это функция, которая просто имеет блок сценария процесса.
Одного этого недостаточно, чтобы убедить меня в том, что фильтр будет иметь преимущество в скорости перед функцией, поскольку оба имеют одинаковые блоки процессов.
И что это за оборудование 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 до того, как были созданы двоичные файлы. :П
Наконец, попробуйте свой тест в новом сеансе 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
Итак, автор ошибался ... и теперь я не чувствую себя плохо из-за того, что никогда раньше не использовал фильтр вместо функции.
На самом деле разница будет намного меньше, если вы используете один и тот же $ _ в обоих тестах. Я не исследовал причину, но полагаю, это потому, что автор не использует одинаковый подход в обоих тестах. Кроме того, вывод на консоль может повлиять на результаты. Если вырезать эти детали, цифры будут очень похожими. Видеть:
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