Skip to content

Commit

Permalink
Version 1.2
Browse files Browse the repository at this point in the history
added Where-ObjectFast and Foreach-ObjectFast
  • Loading branch information
TobiasPSP committed Nov 30, 2019
1 parent ad6ff45 commit acf2fee
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 1 deletion.
102 changes: 102 additions & 0 deletions PSOneTools/1.2/Foreach-ObjectFast.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
function Foreach-ObjectFast
{
<#
.SYNOPSIS
Faster Foreach-Object
.DESCRIPTION
Foreach-ObjectFast can replace the built-in Foreach-Object and improves pipeline speed considerably.
Foreach-ObjectFast supports only the most commonly used parameters -Begin, -Process, and -End, so you can replace
1..100 | Foreach-Object { 'Server{0:d3}' -f $_ }
with
1..100 | Foreach-ObjectFast { 'Server{0:d3}' -f $_ }
but you cannot currently replace instances of Foreach-Object that uses the less commonly used parameters,
like -RemainingScripts, -MemberNames, and -ArgumentList
Foreach-ObjectFast has a performance benefit per iteration, so the more objects
you send through the pipeline, the more significant performace benefits you will see.
Foreach-ObjectFast is using a steppable pipeline internally which performs better.
However because of this, the debugging experience will be different, and internal
variables such as $MyInvocation may yield different results. For most every-day tasks,
these changes are not important.
A complete explanation of what Where-ObjectFast does can be found here:
https://powershell.one/tricks/performance/pipeline
.EXAMPLE
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$result = 1..1000000 | Foreach-ObjectFast -Process {
"I am at $_"
}
$report = '{0} elements in {1:n2} seconds'
$report -f $result.Count, $stopwatch.Elapsed.TotalSeconds
Demos the speed improvements. Run this script to see how well it performs,
then replace Foreach-ObjectFast with the default Foreach-Object, and check out
the performace difference. $result is the same in both cases.
.LINK
https://powershell.one/tricks/performance/pipeline
https://github.com/TobiasPSP/Modules.PSOneTools/blob/master/PSOneTools/1.2/Foreach-ObjectFast.ps1
#>

param
(
# executes for each pipeline element
[ScriptBlock]
$Process,

# executes once before the pipeline is started.
# can be used for initialization routines
[ScriptBlock]
$Begin,

# executes once after all pipeline elements have been processed
# can be used to do cleanup work
[ScriptBlock]
$End
)

begin
{
# construct a hard-coded anonymous simple function from
# the submitted scriptblocks:
$code = @"
& {
begin
{
$Begin
}
process
{
$Process
}
end
{
$End
}
}
"@
# turn code into a scriptblock and invoke it
# via a steppable pipeline so we can feed in data
# as it comes in via the pipeline:
$pip = [ScriptBlock]::Create($code).GetSteppablePipeline($myInvocation.CommandOrigin)
$pip.Begin($true)
}
process
{
# forward incoming pipeline data to the custom scriptblock:
$pip.Process($_)
}
end
{
$pip.End()
}
}
Binary file not shown.
File renamed without changes.
File renamed without changes.
87 changes: 87 additions & 0 deletions PSOneTools/1.2/Where-ObjectFast.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
function Where-ObjectFast
{
<#
.SYNOPSIS
Faster Where-Object
.DESCRIPTION
Where-ObjectFast can replace the built-in Where-Object and improves pipeline speed considerably.
Where-ObjectFast supports only the scriptblock version of Where-Object, so you can replace
Get-Service | Where-Object { $_.Status -eq 'Running' }
with
Get-Service | Where-ObjectFast { $_.Status -eq 'Running' }
but you cannot currently replace the short form of Where-Object:
Get-Service | Where-Object Status -eq Running
Where-ObjectFast has a performance benefit per iteration, so the more objects
you send through the pipeline, the more significant performace benefits you will see.
Where-ObjectFast is using a steppable pipeline internally which performs better.
However because of this, the debugging experience will be different, and internal
variables such as $MyInvocation may yield different results. For most every-day tasks,
these changes are not important.
A complete explanation of what Where-ObjectFast does can be found here:
https://powershell.one/tricks/performance/pipeline
.EXAMPLE
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$result = 1..1000000 | Where-ObjectFast -FilterScript {
$_ % 5
}
$report = '{0} elements in {1:n2} seconds'
$report -f $result.Count, $stopwatch.Elapsed.TotalSeconds
Demos the speed improvements. Run this script to see how well it performs,
then replace Where-ObjectFast with the default Where-Object, and check out
the performace difference. $result is the same in both cases.
.LINK
https://powershell.one/tricks/performance/pipeline
https://github.com/TobiasPSP/Modules.PSOneTools/blob/master/PSOneTools/1.2/Where-ObjectFast.ps1
#>


param
(
# Filter scriptblock that is applied to each pipeline element.
# When the filter scriptblock evaluates to $true, the element can pass,
# else the element is filtered out.
[ScriptBlock]
$FilterScript
)

begin
{
# construct a hard-coded anonymous simple function:
$code = @"
& {
process {
if ($FilterScript)
{ `$_ }
}
}
"@
# turn code into a scriptblock and invoke it
# via a steppable pipeline so we can feed in data
# as it comes in via the pipeline:
$pip = [ScriptBlock]::Create($code).GetSteppablePipeline($myInvocation.CommandOrigin)
$pip.Begin($true)
}
process
{
# forward incoming pipeline data to the custom scriptblock:
$pip.Process($_)
}
end
{
$pip.End()
}
}
File renamed without changes.
4 changes: 3 additions & 1 deletion PSOneTools/1.1/module.psm1 → PSOneTools/1.2/module.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
# LOADING ALL FUNCTION DEFINITIONS:

. $PSScriptRoot\Test-PSOnePort.ps1
. $PSScriptRoot\Test-PSOnePing.ps1
. $PSScriptRoot\Test-PSOnePing.ps1
. $PSScriptRoot\Foreach-ObjectFast.ps1
. $PSScriptRoot\Where-ObjectFast.ps1

0 comments on commit acf2fee

Please sign in to comment.