如何在 PowerShell 中使用 ForEach-Object Parallel cmdlet?
Foreach-Object -Parallel 命令是在 PowerShell 7 预览版 3 中引入的,它用于并行执行管道输入,本文将对此进行更详细的解释。
请注意:Foreach-Object 和 Foreach 命令相同,但我们不能写 Foreach -Parallel 命令,因为没有这样的命令,我们需要使用完整的命令 Foreach-Object -Parallel。
运行并行对象的简单示例。
示例
1..10 | ForEach-Object -Parallel{ $_ * 1000 Sleep 1 }
输出
1000 2000 3000 4000 5000 6000 7000 8000 9000 10000
让我们比较使用和不使用 -Parallel 参数的计时。
并行执行
$time1 = Measure-Command { 1..10 | ForEach-Object -Parallel{ $_ * 1000 Sleep 1 } } Write-Output "Parallel Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "
输出
Parallel Time : Minutes : 0 , Seconds : 2 , Milliseconds : 2500.9792
顺序执行
$time1 = Measure-Command { 1..10 | ForEach-Object { $_ * 1000 Sleep 1 } } Write-Output "Sequential Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "
输出
Sequential Time : Minutes : 0 , Seconds : 10 , Milliseconds : 10062.0786
您可以看到以上两种执行之间的显著差异,并行运行比顺序运行快得多。
还有一个参数支持 foreach-Object 循环的并行化,即 -ThrottleLimit,表示并行执行的线程数。默认情况下,节流限制为 5。请查看增加节流限制后的时间差异。
示例
$time1 = Measure-Command { 1..10 | ForEach-Object -Parallel{ $_ * 1000 Sleep 1 } -ThrottleLimit 10 } Write-Output "Sequential Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "
输出
Parallel Time : Minutes : 0 , Seconds : 1 , Milliseconds : 1615.4921
如果您比较第一个并行时间示例,第二个更快,因为我们增加了节流限制。当您增加节流限制时,请确保哪个命令用于并行执行,以及有多少节流限制作为输入传递,否则系统将因脚本执行而超载,因为生成了许多 PowerShell 线程。
您也可以将此命令作为后台作业运行,因为它支持 -AsJob 参数。
$fjob = 1..10 | ForEach-Object -Parallel{ $_ * 1000 Sleep 1 } -ThrottleLimit 10 -AsJob $fjob | Receive-Job
其他远程命令和 foreach-Object -Parallel 之间的区别在于,此命令在同一上下文中并行运行作业,这称为 命名空间,而其他远程命令则使用 -ComputerName 参数或 Invoke-Command 在远程计算机上顺序运行,这就是并行执行对于远程计算机快得多的原因。
当您在 PS 版本 7 中使用并行 foreach 循环时,并行循环内唯一可见的变量是管道变量,其他外部变量或对象可以使用 Using: 关键字访问。例如:
示例
$computers = "Test1-Win2k12", "test1-Win2k16" $command = "Win32_OperatingSystem" $computers | ForEach-Object -Parallel { Get-CimInstance $using:command -ComputerName $_ }
您可以在上面的脚本中看到,只有 $computers 可以通过 $_ 在 Foreach 循环中访问,但要访问 $command,我们需要使用 $using:Command,因为它在循环的作用域之外,但这在简单的 foreach 循环中并非如此。