使 Powershell 进度条更高效

问题描述

我构建了一个脚本来过滤日志文件中的多个消息。我现在使用的文件大约有 400.000 行,当我寻找与以下代码匹配的文件时,他需要很长时间才能添加进度条。有没有办法让它更有效率。如果我是对的,那么花这么长时间的原因是他每经过一行都会刷新进度条 Gui。

config.action_mailer.show_previews = true

解决方法

更新宿主应用程序中的进度条元素确实会在执行过程中占用时间和资源——但即使你抑制了进度条,写入进度流仍然很慢!

对于 iRon suggests,解决方案是减少调用 Write-Progress 的次数:

$result = Get-Content $path | ForEach-Object {
    # ...
    
    $i++
    if($i % 100 -eq 0){
        Write-Progress -activity "Searching for matches" -status "Scanned: $i of $($length)" -percentComplete (($i / $length)  * 100)
    }
}

这里我们只每 100 行写入一次进度流 - 99% 的更新会影响执行速度:-)

,

详细说明我之前的命令:

众所周知,

Write-Progress 很慢,尤其是在 Windows PowerShell 上。换句话说,如果您使用 Windows PowerShell,我建议您升级(或至少检查)PowerShell Core

为了加快速度,您可以考虑调用 Write-Progress 的次数与您的最大屏幕宽度差不多:

$Length = 400.000
(Measure-Command {
    $MaxScreenWidth = 200
    ForEach($i in (0..$Length)) {
        if ($i % [math]::floor($length / $MaxScreenWidth) -eq 0) { 
            Write-Progress -activity "Searching for matches" -status "Scanned: $i of $($length)" -percentComplete (($i / $length)  * 100)
        }
    }
}).TotalMilliSeconds

对于这个简单的示例,这大约是没有 if ($i % [math]::floor($length / $MaxScreenWidth) -eq 0) { 条件的情况下的两倍(在 Windows PowerShell 上),并且在更多迭代或同时输出到显示器时甚至更快。

注意事项:

  • 上面的例子假设一个连续的序列
  • 假设序列大于最大屏幕宽度
  • 在进行过程中不应更改(减小)屏幕宽度

为了避免上述缺点,您可能会采用更复杂的实现方式,例如:

$Length = 400.000
(Measure-Command {
    ForEach($i in (0..$Length)) {
        $Script:WindowWidthChanged = $Script:WindowWidth -ne $Host.UI.RawUI.WindowSize.Width
        if ($Script:WindowWidthChanged) { $Script:WindowWidth = $Host.UI.RawUI.WindowSize.Width }
        $ProgressCompleted = [math]::floor($i * $Script:WindowWidth / $length)
        if ($Script:WindowWidthChanged -or $ProgressCompleted -ne $Script:LastProgressCompleted) {
            Write-Progress -activity "Searching for matches" -status "Scanned: $i of $($length)" -percentComplete (($i / $length)  * 100)
        }
        $Script:LastProgressCompleted = $ProgressCompleted
    }
}).TotalMilliSeconds