如何为 PowerShell ThreadJobs 中的变量赋值?

问题描述 投票:0回答:2

ThreadJobs 可以访问与启动时相同的环境。
但通常情况下,当尝试从父级别更改变量时,PowerShell 会响应语法错误。

文档 MS Learn - about_Thread_Jobs 有一些见解,但我发现没有什么有用的。

下面的示例说明了尝试使用普通 PowerShell 变量时出现的问题。

[Array]$Numbers = @()

foreach ($i in 0..11) {
    $Jobs = Start-ThreadJob {
        $Using:Numbers += $using:i
    }
}

$Jobs | Wait-Job | Remove-Job

$Numbers

ParserError: 
Line |
   6 |          $Using:Numbers += $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.
multithreading powershell jobs
2个回答
1
投票

由于线程是并行运行的,因此如果两个或多个线程尝试同时对对象执行操作,则必须有某种方法来防止父对象损坏或 ThreadJob 失败。

在与线程安全执行的概念进行了几天的斗争之后(并在 Santiago Squarzon 的耐心下得到了很大的帮助) 和其他人,我自己的结论是:

线程中的所有操作都必须是线程安全的(因此得名)。

  1. 如果对象是“普通”对象,请勿尝试使用
    Using:
    设置值,除非您可以保证该值已被锁定
  2. 即使使用线程安全对象,也不要尝试同时读取和写入该值,除非您可以保证该值已在两个操作之间被锁定
  3. 仅使用提供的线程安全方法来操作线程安全对象中的数据,除非您可以保证该值已被锁定

在.Net中,我发现了两个可以使用的线程安全类

(每个 T 引用都有一个可用的类名称。)

这些类都没有用于递增值的线程安全方法。

因此,PowerShell 7.x 中的线程安全 ThreadJob,仅向父对象添加新项目,可能如下所示

$SafeNumbers = [System.Collections.Concurrent.ConcurrentBag[object]]::new()

foreach ($i in 0..11) {
    $Thread = Start-ThreadJob {
        ($Using:SafeNumbers).Add($Using:i)
    }
}

Get-Job | Wait-Job | Remove-Job

$SafeNumbers.ToArray()

11
10
9
8
7
6
5
4
3
2
1
0

当然不能保证输出的顺序。


0
投票

经过一番搜索,我找到了一个解决变量引用显然有效的方法......

但是它迟早会失败,所以不要使用这个例子。

[Array]$Numbers = @()
$refNumbersVar = Get-Variable Numbers

foreach ($i in 0..11) {
    $Jobs = Start-ThreadJob {
        ($Using:refNumbersVar).Value += $using:i
    }
}

$Jobs | Wait-Job | Remove-Job

$Numbers

编辑:警告所有人不要使用此示例。

© www.soinside.com 2019 - 2024. All rights reserved.