PowerShell: スクリプトが並列で実行される

PowerShell: スクリプトが並列で実行される

で実行すると、次のスクリプトは並列ブロックの開始前に宣言された変数を-Parallel渡しません。代わりに、null 値になります。スクリプトが で実行されていない場合は問題にはなりません。スクリプトは変数値を渡し、期待どおりに実行されます。参考までに、私は PS 7.x を実行しています。$basePath-Parallel

$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"

答え1

したがって、PowerShell の新しいスキームでは、並列ループ内のすべての呼び出しに対して だけではなく-parallelを使用する必要があります。これは、変数が親スコープで定義されているためです。$using:basePath$basePath

マルチスレッドおよび並列操作では、同時実行性またはマルチ同時実行の問題として総称される一連の特有の複雑な問題が発生するため、スレッドによってアクセスされるメモリが安全に使用できる状態であることを保証するために特別な手順を実行する必要があります。

Powershell は、RunSpace と呼ばれるスレッド コンテキストを実装し、並列操作ごとに 1 つ作成します。runspace には、そのブロックで宣言されたすべての変数のコピーが含まれており、コピーされた変数のインスタンスに対してのみ操作できます。つまり、1 つのスレッドが変数のバージョンを変更しても、他のスレッドはその変更を認識しません。

ただし、複数のスレッドのスコープ内にある変数にアクセスするには、Mutex や Locks などのテクニックを検討する必要があります。スレッド ロックは、使用中に値が変更されないようにするシンプルな構造です。Powershell では、より$using:スコープの高い変数を参照するためのキーワードを追加することで、これを簡単に行えるようになりました。

詳細については、こちらをご覧ください:詳しくはこちら:

関連情報