I'm reading currently the Windows PowerShell 3.0 Step by Step book to get some more insights to PowerShell.
On page 201 the author demonstrates that a filter is faster than the function with the same functionally.
This script takes 2.6 seconds on his computer:
MeasureAddOneFilter.ps1
Filter AddOne
{
"add one filter"
$_ + 1
}
Measure-Command { 1..50000 | addOne }
and this one 4.6 seconds
MeasureAddOneFunction.ps1
Function AddOne
{
"Add One Function"
While ($input.moveNext())
{
$input.current + 1
}
}
Measure-Command { 1..50000 | addOne }
If I run this code is get the exact opposite of his result:
.\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
Can someone explain this to me?
Unless the author gave more supporting evidence, maybe he was just full of hot air. You've run the test and got the result and proven him wrong.
Edit: From Jeffrey Snover's blog:
That alone isn't enough to convince me that a filter is going to have a speed advantage over a function, given both have identical process blocks.
Also what sort of 1950's equipment is that guy on where it takes 4.6 seconds to add one to a number?
4.6 seconds is whack. Maybe the author was using some sort of CTP version of Powershell before the binaries were ngen'ed. :P
Finally, try your test in a new Powershell session, but in reverse order. Try the Function first and the Filter second, or vice versa:
See? The first one you run will always be slower. It was just about the .NET internals of having already loaded stuff into memory that makes the second operation faster, regardless of whether it's a function or a filter.
I will admit though that the Function still seems to be consistently faster than the Filter, regardless of how many times it's run.
So the author was wrong... and now I don't feel bad for never having ever used a Filter instead of a Function before.
Actually the difference is much smaller if you use the same $_ in both tests. I didn't investigate the cause, but I suppose it's because the author is not using the same approach in both tests. Also, console output can interfere in the results. If you cut these parts, the numbers are very similar. See:
The results will be very close, even if you change the order of the commands.
The documentation also says that Filters are basically shortcuts to functions with only the process block. Functions, unless specified with a process block (or some other technique like using automatic variables such as $input), run once, don't use input and don't pass to the next command in the pipeline.
More info at https://technet.microsoft.com/en-us/library/hh847829.aspx and https://technet.microsoft.com/en-us/library/hh847781.aspx
In a PS pipeline a function gets run once, unless a process block is used. A filter is a function with an implied process block. If you wanted to compare the speed of a function and a filter you must either use a process block in the function or add a foreach in the pipeline; e.g: 1..50000 | addOne # filter or function with process test 1..50000 | % { addOne $_ } # function without process block test The result will then be similar as shown earlier in this post.