ZetCode

PowerShell Foreach-Object -Parallel

最后修改:2025 年 2 月 15 日

本教程涵盖 PowerShell 中的 Foreach-Object -Parallel cmdlet。它支持并行处理管道输入,以提高性能。并行执行可以显著加快处理大型数据集的操作速度。该 cmdlet 是作为 PowerShell Core 的一部分在 PowerShell 7.0 中引入的。

并行处理基础知识

并行处理同时执行多个操作。在 PowerShell 中,这是通过 Foreach-Object -Parallel 实现的。它以并发方式处理管道项,而不是顺序处理。每次迭代都在单独的 PowerShell runspace 中运行。这对于 CPU 密集型或 I/O 密集型操作非常理想。

基本并行处理

最简单的用法是以并行方式处理每个输入项。默认情况下,它使用多达 5 个并行线程。脚本块包含要执行的操作。$_ 变量表示当前管道项。

parallel1.ps1
1..10 | Foreach-Object -Parallel {
    "Processing item $_"
    Start-Sleep -Milliseconds 500
}

此示例并行处理数字 1 到 10。每次迭代休眠 500 毫秒。由于并行执行,输出顺序可能会有所不同。请注意,与顺序处理相比,项完成得更快。

控制线程数

-ThrottleLimit 参数控制最大并行线程数。较高的值会增加并发性,但会消耗更多资源。较低的值会减少资源使用,但会降低速度。最佳值取决于您的系统和工作负载。

parallel2.ps1
1..20 | Foreach-Object -Parallel {
    "Processing item $_ (Thread $PID)"
    Start-Sleep -Seconds 1
} -ThrottleLimit 3

此示例将处理限制为 3 个并发线程。$PID 显示每个 runspace 的进程 ID。请注意,只有 3 个项同时处理。根据您的系统能力调整吞吐量限制。

使用外部变量

-Using 范围修饰符可以访问外部变量。默认情况下,并行脚本块具有隔离的范围。这可以防止竞态条件,但需要显式共享。使用 $using:variableName 引用外部变量。

parallel3.ps1
$prefix = "Result"
1..5 | Foreach-Object -Parallel {
    "$($using:prefix): $_ squared is $($_ * $_)"
}

此示例使用外部 $prefix 变量。每次迭代都会计算数字的平方。$using: 前缀访问外部变量。输出将前缀与计算结果结合起来。

并行错误处理

错误处理方式与顺序处理类似。Try/Catch 块可以捕获并行过程中的异常。错误会在完成后汇总并报告。使用 -ErrorAction 控制错误行为。

parallel4.ps1
1..5 | Foreach-Object -Parallel {
    try {
        if ($_ % 2 -eq 0) {
            throw "Even number error"
        }
        "Processed odd $_"
    }
    catch {
        "Error processing $_: $_"
    }
}

此示例为偶数引发错误。奇数正常处理,没有错误。每个错误都会被单独捕获和处理。输出清晰地显示了成功和失败的项。

从并行中返回对象

并行块可以将对象返回到管道。输出会被收集并在所有项完成后发出。返回的对象会保留其原始类型。这使得进一步的管道处理成为可能。

parallel5.ps1
$results = 1..10 | Foreach-Object -Parallel {
    [PSCustomObject]@{
        Number = $_
        Square = $_ * $_
        IsEven = $_ % 2 -eq 0
    }
}

$results | Format-Table

此示例为每个数字返回自定义对象。每个对象包含数字、其平方和奇偶性。结果收集在 $results 变量中。Format-Table 整齐地显示收集的数据。

并行文件处理

并行处理非常适合 I/O 密集型操作。文件操作可以从并行执行中获得巨大的好处。此示例并发处理多个文件。Measure-Command 显示了性能提升。

parallel6.ps1
$files = Get-ChildItem -Path "C:\Temp\*.log"
Measure-Command {
    $files | Foreach-Object -Parallel {
        $content = Get-Content $_.FullName
        "$($_.Name) has $($content.Count) lines"
    } -ThrottleLimit 10
}

此示例并行处理所有 .log 文件。每个文件的行数都会被计算并报告。将 ThrottleLimit 增加以更好地利用 I/O。Measure-Command 显示总执行时间。

并行 API 请求

Web 请求非常适合并行处理。每个请求独立于其他请求运行。这大大缩短了总执行时间。使用 Invoke-RestMethod 进行 API 调用。

parallel7.ps1
$urls = @(
    "https://api.github.com/users/powershell"
    "https://api.github.com/users/microsoft"
    "https://api.github.com/users/github"
)

$urls | Foreach-Object -Parallel {
    try {
        $response = Invoke-RestMethod -Uri $_
        "User $($response.login) has $($response.public_repos) repos"
    }
    catch {
        "Failed to fetch $_"
    }
}

此示例并行获取 GitHub 用户数据。每个 URL 都被并发处理。结果显示用户名和存储库计数。错误会被捕获并得到妥善处理。

复杂的并行工作流

并行处理可以组合多个操作。此示例展示了一个完整的数据处理工作流。它演示了变量共享和结果聚合。-AsJob 参数将处理作为后台任务运行。

parallel8.ps1
$data = 1..100
$results = @{}
$job = $data | Foreach-Object -Parallel {
    $square = $_ * $_
    $cube = $_ * $_ * $_
    $results = @{
        Number = $_
        Square = $square
        Cube = $cube
    }
    $using:results[$_] = $results
} -ThrottleLimit 10 -AsJob

$job | Wait-Job
$results.GetEnumerator() | Sort-Object Key | Select-Object -First 5

此示例并行计算平方和立方。结果存储在共享的哈希表中。-AsJob 参数启用后台处理。最终输出显示前 5 个计算结果。

来源

PowerShell 文档

本教程涵盖了 PowerShell 中的 Foreach-Object -Parallel cmdlet。并行处理可以显著提高脚本性能。请记住在线程数与系统资源之间取得平衡。正确的错误处理可确保可靠的并行执行。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PowerShell 教程