Я в основном строю свою собственную функцию параллельного конвейера foreach, используя пространства выполнения.
Моя проблема: я вызываю свою функцию следующим образом:
somePipeline | MyNewForeachFunction { scriptBlockHere } | pipelineGoesOn...
Как мне передать $_
параметр правильно в ScriptBlock?Он работает, когда ScriptBlock содержит в качестве первой строки
param($_)
Но, как вы могли заметить, встроенные в PowerShell ForEach-Object и Where-Object not нуждаются в таком объявлении параметрав каждом ScriptBlock, который передается им.
Спасибо за ваши ответы заранее fjf2002
РЕДАКТИРОВАТЬ:
Цель: я хочу утешения дляпользователи функции MyNewForeachFunction
- им не нужно писать строку param($_)
в своих блоках скрипта.
Внутри 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, Почему рабочий процесс PowerShell значительно медленнее, чем сценарий без рабочего процесса для анализа файлов XML