我基本上是使用运行空间构建自己的并行 foreach 管道函数。
我的问题是:我这样调用我的函数:
somePipeline | MyNewForeachFunction { scriptBlockHere } | pipelineGoesOn...
我怎样才能通过$_
参数是否正确输入到 ScriptBlock 中?当 ScriptBlock 包含作为第一行时它起作用
param($_)
但正如您可能已经注意到的,powershell 内置的 ForEach-Object 和Where-Object 会执行以下操作:not在传递给它们的每个 ScriptBlock 中都需要这样的参数声明。
感谢您提前的答复
FJF2002
EDIT:
目标是:我希望功能用户感到舒适MyNewForeachFunction
- 他们不需要写一行param($_)
在他们的脚本块中。
Inside MyNewForeachFunction
, ScriptBlock 当前通过以下方式调用
$PSInstance = [powershell]::Create().AddScript($ScriptBlock).AddParameter('_', $_)
$PSInstance.BeginInvoke()
EDIT2:
重点是,例如内置函数是如何实现的ForEach-Object
实现这一点$_
不需要在其 ScriptBlock 参数中声明为参数,我也可以使用该功能吗?
(如果答案是,ForEach-Object
是一个内置函数,并且使用了一些我无法使用的魔法,那么在我看来,这将取消 PowerShell 语言的整体资格)
EDIT3:
感谢 mklement0,我终于可以构建我的通用 foreach 循环。这是代码:
function ForEachParallel {
[CmdletBinding()]
Param(
[Parameter(Mandatory)] [ScriptBlock] $ScriptBlock,
[Parameter(Mandatory=$false)] [int] $PoolSize = 20,
[Parameter(ValueFromPipeline)] $PipelineObject
)
Begin {
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $poolSize)
$RunspacePool.Open()
$Runspaces = @()
}
Process {
$PSInstance = [powershell]::Create().
AddCommand('Set-Variable').AddParameter('Name', '_').AddParameter('Value', $PipelineObject).
AddCommand('Set-Variable').AddParameter('Name', 'ErrorActionPreference').AddParameter('Value', 'Stop').
AddScript($ScriptBlock)
$PSInstance.RunspacePool = $RunspacePool
$Runspaces += New-Object PSObject -Property @{
Instance = $PSInstance
IAResult = $PSInstance.BeginInvoke()
Argument = $PipelineObject
}
}
End {
while($True) {
$completedRunspaces = @($Runspaces | where {$_.IAResult.IsCompleted})
$completedRunspaces | foreach {
Write-Output $_.Instance.EndInvoke($_.IAResult)
$_.Instance.Dispose()
}
if($completedRunspaces.Count -eq $Runspaces.Count) {
break
}
$Runspaces = @($Runspaces | where { $completedRunspaces -notcontains $_ })
Start-Sleep -Milliseconds 250
}
$RunspacePool.Close()
$RunspacePool.Dispose()
}
}
部分代码来自 MathiasR.Jessen,为什么用于 XML 文件分析的 PowerShell 工作流明显慢于非工作流脚本