Powershell Foreach-Object -Parallel 如何在循环外更改变量的值跟踪进度

问题描述

代码打印一个简单的进程,一次做一件事:

$files = 1..100
$i = 0
$files | Foreach-Object {
    $progress = ("#" * $i)
    Write-Host  "`r$progress" -NoNewLine
    $i ++
    Start-Sleep -s 0.1
}

但是如果我想同时并行做两件事,我无法输出进度,因为我无法在并行循环之外更改变量。这不符合要求:

$files = 1..100
$i = 0
$files | Foreach-Object -ThrottleLimit 2 -Parallel {
    $progress = ("#" * $i)
    Write-Host  "`r$progress" -NoNewLine
    $i ++
    Start-Sleep -s 0.1
}

我找不到一个好的解决方案来访问外部变量,不仅要使用 $Using 读取它,还要更改它。这在 Powershell 7 中甚至是可能的吗?

解决方法

根据本文 - PowerShell ForEach-Object Parallel Feature - 您可以使用 $using 关键字从“外部”脚本中引用变量:

例如

$files = 1..100
$i = 100;
$files | Foreach-Object -ThrottleLimit 2 -Parallel {
    write-host ($using:i)
    Start-Sleep -s .1
}
# 100
# 100
# etc

但是如果您尝试更新该值,您将得到:

$files | Foreach-Object -ThrottleLimit 2 -Parallel {
    $using:i += $using:i
    Start-Sleep -s .1
}

ParserError:
Line |
   2 |      $using:i += $using:i
     |      ~~~~~~~~
     | The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
     | assignments,such as a variable or a property.

基本上,您不能将 back 分配给 $using:i 变量。

可以做的是改变一个复杂对象的属性——例如这个:

$counter = @{ "i" = 0 }
$files | Foreach-Object -ThrottleLimit 2 -Parallel {
     ($using:counter).i = ($using:counter).i + 1
     Start-Sleep -s .1
}
$counter

# Name                           Value
# ----                           -----
# i                              100
#

它允许您更新值,但可能不是(可能不会)是线程安全的。

,

我认为这是正确的,基于 Writing Progress across multiple threads with Foreach ParallelIt may be missing a lock,但仅就写作进度而言,这可能没什么大不了的。在这种情况下,您也可以使用文件名作为进度。

$hash = @{i = 1}
$sync = [System.Collections.Hashtable]::Synchronized($hash)

$files = 1..100
$files | Foreach-Object -throttlelimit 2 -parallel {
    $syncCopy = $using:sync
    $progress = '#' * $syncCopy.i
    #$progress = '#' * $_
    Write-Host  "`r$progress" -NoNewLine
    $syncCopy.i++
    Start-Sleep .1
}

输出:

####################################################################################################

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...