1..2 | ForEach-Object { 'begin' } { 'process A' } { 'process B' } { 'end' }
begin
process A
process B
process A
process B
第一个脚本块始终映射到块 begin
,最后一个块映射到块 end
,两者之间的块都映射到块 process
。
示例 10:为每个管道项运行多个脚本块
如上一示例所示,使用 Process 参数传递的多个脚本块映射到 Begin 和 End 参数。 若要避免此映射,必须为 Begin 和 End 参数提供显式值。
1..2 | ForEach-Object -Begin $null -Process { 'one' }, { 'two' }, { 'three' } -End $null
three
three
示例 11:并行批处理运行慢脚本
此示例运行一个脚本块,该脚本块计算字符串并休眠一秒钟。
$Message = "Output:"
1..8 | ForEach-Object -Parallel {
"$using:Message $_"
Start-Sleep 1
} -ThrottleLimit 4
Output: 1
Output: 2
Output: 3
Output: 4
Output: 5
Output: 6
Output: 7
Output: 8
ThrottleLimit 参数值设置为 4,以便四个批次处理输入。
关键字 $using:
用于将 $Message
变量传递到每个并行脚本块。
示例 12:并行检索日志条目
此示例从本地 Windows 计算机上的 5 个系统日志中检索 50,000 个日志条目。
$logNames = 'Security','Application','System','Windows PowerShell','Microsoft-Windows-Store/Operational'
$logEntries = $logNames | ForEach-Object -Parallel {
Get-WinEvent -LogName $_ -MaxEvents 10000
} -ThrottleLimit 5
$logEntries.Count
50000
Parallel 参数指定为每个输入日志名称并行运行的脚本块。 ThrottleLimit 参数可确保所有五个脚本块同时运行。
示例 13:作为作业并行运行
此示例创建一个作业,该作业并行运行一个脚本块,一次运行两个脚本块。
$job = 1..10 | ForEach-Object -Parallel {
"Output: $_"
Start-Sleep 1
} -ThrottleLimit 2 -AsJob
$job | Receive-Job -Wait
Output: 1
Output: 2
Output: 3
Output: 4
Output: 5
Output: 6
Output: 7
Output: 8
Output: 9
Output: 10
变量 $job
接收收集输出数据和监视运行状态的作业对象。
作业对象通过管道连接到 Receive-Job
Wait 开关参数,该参数将输出流式传输到控制台,就像 ForEach-Object -Parallel
在没有 AsJob 的情况下运行一样。
示例 14:使用线程安全变量引用
此示例并行调用脚本块以收集唯一命名的 Process 对象。
$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
Get-Process | ForEach-Object -Parallel {
$dict = $using:threadSafeDictionary
$dict.TryAdd($_.ProcessName, $_)
$threadSafeDictionary["pwsh"]
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
82 82.87 130.85 15.55 2808 2 pwsh
ConcurrentDictionary 对象的单个实例传递到每个脚本块以收集对象。 由于 ConcurrentDictionary 是线程安全的,因此可以安全地由每个并行脚本进行修改。 此处使用非线程安全对象(如 System.Collections.Generic.Dictionary)是不安全的。
此示例使用 Parallel 参数的效率非常低。 该脚本只是将输入对象添加到并发字典对象。 这是微不足道的,不值得在单独的线程中调用每个脚本的开销。 ForEach-Object
在没有并行开关的情况下正常运行会更高效、更快。 此示例仅用于演示如何使用线程安全变量。
示例 15:并行执行时写入错误
此示例并行写入错误流,其中写入错误的顺序是随机的。
1..3 | ForEach-Object -Parallel {
Write-Error "Error: $_"
Write-Error: Error: 1
Write-Error: Error: 3
Write-Error: Error: 2
示例 16:并行执行中的终止错误
此示例演示一个并行运行的 scriptblock 中的终止错误。
1..5 | ForEach-Object -Parallel {
if ($_ -eq 3)
throw "Terminating Error: $_"
Write-Output "Output: $_"
Exception: Terminating Error: 3
Output: 1
Output: 4
Output: 2
Output: 5
Output: 3
永远不会写入 ,因为该迭代的并行脚本块已终止。
即使使用 $using:
关键字,也不支持Foreach-Object -Parallel
PipelineVariable 通用参数变量。
示例 17:在嵌套并行脚本 ScriptBlockSet 中传递变量
可以在作用域内 scriptblock 外部 Foreach-Object -Parallel
创建变量,并在脚本块中使用该变量和 $using
关键字。
$test1 = 'TestA'
1..2 | Foreach-Object -Parallel {
$using:test1
TestA
TestA
# You CANNOT create a variable inside a scoped scriptblock
# to be used in a nested foreach parallel scriptblock.
$test1 = 'TestA'
1..2 | Foreach-Object -Parallel {
$using:test1
$test2 = 'TestB'
1..2 | Foreach-Object -Parallel {
$using:test2
Line |
2 | 1..2 | Foreach-Object -Parallel {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
| The value of the using variable '$using:test2' cannot be retrieved because it has not been set in the local session.
嵌套脚本块无法访问变量 $test2
,并引发错误。
示例 18:创建多个并行运行脚本的作业
ThrottleLimit 参数限制在每个 实例 ForEach-Object -Parallel
期间运行的并行脚本数。 它不会限制使用 AsJob 参数时可以创建的作业数。 由于作业本身是并发运行的,因此可以创建多个并行作业,每个作业的运行上限为并发脚本块的限制数。
$jobs = for ($i=0; $i -lt 10; $i++) {
1..10 | ForEach-Object -Parallel {
./RunMyScript.ps1
} -AsJob -ThrottleLimit 5
$jobs | Receive-Job -Wait
此示例创建 10 个正在运行的作业。 每个作业不能同时运行超过 5 个脚本。 并发运行的实例总数限制为 50 (10 个作业, 即 ThrottleLimit 为 5) 。
-ArgumentList
指定方法调用的参数数组。 有关 ArgumentList 行为的详细信息,请参阅 about_Splatting。
已在 Windows PowerShell 3.0 中引入了此参数。
Type:Object[]
Aliases:Args
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-AsJob
导致并行调用作为 PowerShell 作业运行。 返回单个作业对象,而不是来自正在运行的脚本块的输出。 作业对象包含运行的每个并行脚本块的子作业。 所有 PowerShell 作业 cmdlet 都可以使用该作业对象来监视运行状态和检索数据。
此参数是在 PowerShell 7.0 中引入的。
Type:SwitchParameter
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Begin
指定在此 cmdlet 处理任何输入对象之前运行的脚本块。 此脚本块仅针对整个管道运行一次。 有关 块的详细信息 begin
,请参阅 about_Functions。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Confirm
提示你在运行 cmdlet 之前进行确认。
Type:SwitchParameter
Aliases:cf
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
指定在此 cmdlet 处理所有输入对象后运行的脚本块。 此脚本块仅针对整个管道运行一次。 有关 块的详细信息 end
,请参阅 about_Functions。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-InputObject
指定输入对象。 ForEach-Object
在每个输入对象上运行脚本块或操作语句。 输入一个包含对象的变量,或键入可获取对象的命令或表达式。
将 InputObject 参数与 一起使用 ForEach-Object
时,而不是将命令结果传递给 ForEach-Object
时, InputObject 值被视为单个对象。 即使值是命令的结果(如 -InputObject (Get-Process)
)的集合,也是如此。
由于 InputObject 无法从对象的数组或集合中返回单个属性,因此,如果你使用 ForEach-Object
对具有已定义属性中特定值的对象的集合执行操作,请在 ForEach-Object
管道中使用 ,如本主题中的示例所示。
Type:PSObject
Position:Named
Default value:None
Accept pipeline input:True
Accept wildcard characters:False
-MemberName
指定要获取的属性或要调用的方法。
允许使用通配符,但仅在生成的字符串解析为唯一值时才有效。
例如,如果运行 Get-Process | ForEach -MemberName *Name
,则通配符模式匹配多个成员,导致命令失败。
已在 Windows PowerShell 3.0 中引入了此参数。
Type:String
Position:0
Default value:None
Accept pipeline input:False
Accept wildcard characters:True
-Parallel
指定用于并行处理输入对象的脚本块。 输入描述该操作的脚本块。
此参数是在 PowerShell 7.0 中引入的。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Process
指定对每个输入对象所执行的操作。 此脚本块针对管道中的每个对象运行。 有关 块的详细信息 process
,请参阅 about_Functions。
向 Process 参数提供多个脚本块时,第一个脚本块始终映射到块 begin
。 如果只有两个脚本块,则第二个块映射到块 process
。 如果有三个或更多个脚本块,则第一个脚本块始终映射到 begin
块,最后一个块映射到 块 end
,两者之间的块都映射到 块 process
。
Type:ScriptBlock[]
Position:0
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-RemainingScripts
指定 Process 参数不采用的所有脚本块。
已在 Windows PowerShell 3.0 中引入了此参数。
Type:ScriptBlock[]
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-ThrottleLimit
指定并行的脚本块数。 输入对象被阻止,直到正在运行的脚本块计数低于 ThrottleLimit。 默认值为 5
。
ThrottleLimit 参数限制在每个 实例 ForEach-Object -Parallel
期间运行的并行脚本数。 它不会限制使用 AsJob 参数时可以创建的作业数。 由于作业本身是并发运行的,因此可以创建多个并行作业,每个作业的运行上限为并发脚本块的限制数。
此参数是在 PowerShell 7.0 中引入的。
Type:Int32
Position:Named
Default value:5
Accept pipeline input:False
Accept wildcard characters:False
-TimeoutSeconds
指定等待并行处理所有输入的秒数。 在指定的超时时间过后,所有正在运行的脚本都会停止。 将忽略要处理的任何剩余输入对象。 默认值 0
将禁用超时,并且可以 ForEach-Object -Parallel
无限期运行。 在命令行中键入 Ctrl+C 会停止正在运行 ForEach-Object -Parallel
的命令。 此参数不能与 AsJob 参数一起使用。
此参数是在 PowerShell 7.0 中引入的。
Type:Int32
Position:Named
Default value:0
Accept pipeline input:False
Accept wildcard characters:False
-UseNewRunspace
使并行调用为每个循环迭代创建新的运行空间,而不是重用运行空间池中的运行空间。
此参数是在 PowerShell 7.1 中引入的
Type:SwitchParameter
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
-WhatIf
显示运行该 cmdlet 时会发生什么情况。 cmdlet 未运行。
Type:SwitchParameter
Aliases:wi
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
PSObject
你可以通过管道将任何对象传递给此 cmdlet。
PSObject
此 cmdlet 返回由输入确定的对象。
PowerShell 包含以下别名 ForEach-Object
:
所有平台:
foreach
cmdlet ForEach-Object
的工作方式与 Foreach 语句非常类似,只不过不能通过管道将输入传递给 Foreach 语句。 有关 Foreach 语句的详细信息,请参阅 about_Foreach。
从 PowerShell 4.0 开始, Where
ForEach
添加了 用于集合的方法。 可在此处阅读有关这些新方法 的详细信息about_arrays
使用 ForEach-Object -Parallel
:
参数 ForEach-Object -Parallel
集使用 PowerShell 的内部 API 在新运行空间中运行每个脚本块。 这比 ForEach-Object
按顺序处理正常运行的开销要大得多。 与脚本块执行的工作相比,并行运行的开销较小,请务必使用 Parallel 。 例如:
- 多核计算机上的计算密集型脚本
- 花费时间等待结果或执行文件操作的脚本
使用 Parallel 参数可能会导致脚本运行速度比平常慢得多。 尤其是并行脚本是普通脚本时。 使用 Parallel 进行试验,以发现它可能有益的位置。
并行运行时,如果用 ScriptProperties 或 ScriptMethods 修饰的对象在与最初附加到它们的脚本不同的运行空间中运行,则不能保证它们正常运行。
脚本块调用始终尝试在其 主 运行空间中运行,无论实际调用的位置如何。 但是, ForEach-Object -Parallel
会创建在使用后删除的临时运行空间,因此没有运行空间供脚本再执行。
只要 主 运行空间仍然存在,此行为就可以正常工作。 但是,如果脚本依赖于仅存在于调用方运行空间而不是 主 运行空间中的外部变量,则可能无法获得所需的结果。
非终止性错误将写入 cmdlet 错误流,因为它们在并行运行的 scriptblock 中发生。 由于并行 scriptblock 执行顺序是不确定的,因此错误在错误流中的出现顺序是随机的。 同样,写入其他数据流(如警告、详细或信息)的消息将按不确定的顺序写入这些数据流。
终止错误(如异常)会终止发生这些错误的 scriptblock 的单个并行实例。 一个脚本块中的终止错误不会导致 cmdlet 终止 Foreach-Object
。 其他并行运行的脚本块将继续运行,除非它们也遇到终止错误。 终止错误作为 ErrorRecord 写入错误数据流, 其 FullyQualifiedErrorId 为 PSTaskException
。
终止错误可以使用 PowerShell try
/catch
或 trap
块转换为非终止错误。
即使使用 $using:
关键字,并行方案也不支持 PipelineVariable 通用参数变量。
参数 ForEach-Object -Parallel
集在单独的进程线程上并行运行脚本块。 关键字 $using:
允许将变量引用从 cmdlet 调用线程传递到每个正在运行的脚本块线程。 由于脚本块在不同的线程中运行,因此必须安全地使用引用传递的对象变量。 通常,从不更改的引用对象读取数据是安全的。 但是,如果要修改对象状态,则必须使用线程安全对象,例如 .NET System.Collection.Concurrent 类型 (请参阅示例 11) 。