PowerShell 5中BeginInvoke<TInput,TOutput>重载的输入参数传递问题
PowerShell 5 并行处理中 BeginInvoke<TInput,TOutput> 输入传递问题解决
核心错误分析
- 参数类型定义错误:
BeginInvoke的$Inputs集合中的单个元素会作为管道输入传递给脚本块,而非整个PSDataCollection集合。因此脚本块参数不应定义为[System.Management.Automation.PSDataCollection],而是对应集合中元素的类型(这里是PSObject或自定义对象)。 - 管道输入处理缺失:使用
ValueFromPipeline时,脚本块需要通过process块来处理管道输入(PowerShell 脚本块默认只在end块执行,无法接收管道传递的单个元素)。 - 取值逻辑错误:脚本块中无需通过
$Bias[0]取值,因为参数已经接收的是$Inputs中的单个对象。
修正后的代码
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, 5) $RunspacePool.Open() $Inputs = New-Object 'System.Management.Automation.PSDataCollection[PSObject]' $Outputs = New-Object 'System.Management.Automation.PSDataCollection[PSObject]' # 添加输入元素 $Inputs.Add([PSCustomObject]@{ Bias = 100 }) $ScriptBlock = { Param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [PSObject]$InputObject # 接收单个输入元素 ) # 使用process块处理管道输入 process { (Get-Random -Maximum 100) + $InputObject.Bias } } $Instances = (1..10) | ForEach-Object { $Instance = [powershell]::Create().AddScript($ScriptBlock) $Instance.RunspacePool = $RunspacePool [PSCustomObject]@{ Instance = $Instance State = $Instance.BeginInvoke($Inputs,$Outputs) } } # 等待所有线程完成 while ($Instances.State.IsCompleted -contains $False) { Start-Sleep -Milliseconds 100 } # 输出结果 $Outputs
关键原理说明
BeginInvoke<TInput,TOutput>的$Inputs参数本质是管道输入数据源:脚本块会以管道处理的方式逐个接收集合中的元素,而非一次性获取整个集合。- 当你创建多个
[powershell]实例并关联同一个$Inputs时,每个实例都会独立处理整个$Inputs集合中的元素(因此你会得到10个结果,每个都是随机数+100)。 - 如果需要让不同实例处理
$Inputs中的不同元素,可以在$Inputs中添加多个元素,PowerShell 会自动将元素分配给空闲的 runspace 实例。
内容的提问来源于stack exchange,提问作者Newtown
相关产品推荐
相关产品推荐

