在运行时-Parallel
,以下脚本不会传递$basePath
并行块开始之前声明的变量。相反,它是一个空值。当脚本未在其中运行时,这不是问题-Parallel
——它将传递变量值并按预期运行。仅供参考,我正在运行 PS 7.x。
$basePath=((get-location) -replace "\\", "\\")
get-childitem *.tif -recurse | foreach-object -Parallel {
$a=($_ -split "\.tif")[0]
$path=(((split-path $_) -replace "$basePath", "O:\OD\FM\OneDrive\FM\Family Photos") -replace "TIF", "JPG")
$b=(($a -replace "$basePath", "O:\OD\FM\OneDrive\FM\Family Photos") -replace "TIF", "JPG")
if (!(Test-Path -path $path)) {mkdir "$path"}
if (!([system.io.file]::Exists("$b.jpg"))) {
magick convert "$a.tif" -resize 50% -quality 100 -define jpeg:extent=1024KB "$b.jpg"
[console]::foregroundcolor="Green"
echo "`nB`:`t$b`n`n"
}
} -ThrottleLimit 8
[console]::foregroundcolor="White"
因此,在 powershells 新
-parallel
方案中,您需要使用$using:basePath
而不是仅$basePath
用于并行循环内的所有调用。这是因为变量是在父作用域中定义的。多线程和并行操作带来了一组独特的复杂性,统称为并发或多并发问题,因此需要采取特殊步骤来确保线程访问的内存处于安全状态以供使用。
Powershell 实现了一个称为 RunSpace 的线程上下文,并为每个并行操作创建一个。运行空间包含该块中声明的每个变量的副本,并且只能对这些复制的变量实例进行操作。这意味着如果一个线程修改了他们的变量版本,其他线程将不会看到这种变化。
然而,为了访问多线程范围内的变量,我们必须研究诸如互斥锁和锁之类的技术。线程锁是一种简单的构造,可防止在使用值时对其进行修改。在 Powershell 中,他们通过添加
$using:
用于引用更高范围变量的关键字使这变得简单。有关更多详细信息,请参见此处:https ://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/