【问题标题】:Modifying PowerShell $using scope variables in thread started with Start-ThreadJob在使用 Start-ThreadJob 启动的线程中修改 PowerShell $using 范围变量
【发布时间】:2021-06-21 08:44:22
【问题描述】:

如果我理解PowerShell Scopes documentation,应该可以从使用Start-ThreadJob 启动的线程分配给$using 范围变量。文档说(强调我的):

Using 范围修饰符在以下上下文中受支持:

  • ...
  • 线程作业,通过Start-ThreadJobForEach-Object -Parallel 启动(单独的线程会话

根据上下文,嵌入的变量值要么是调用者范围内数据的独立副本,要么是对其的引用
...
在线程会话中,它们通过引用传递。这意味着可以在不同的线程中修改调用范围变量。要安全地修改变量需要线程同步。

但以下运行失败:

$foo = 1

Start-ThreadJob {
    Write-Host $using:foo
    $using:foo = 2
} | Wait-Job | Out-Null

Write-Host $foo

$using:foo = 2 出现错误:

赋值表达式无效。赋值运算符的输入必须是能够接受赋值的对象,例如变量或属性。

使用Write-Host $using:foo 打印变量可以正常工作。

我使用的是 PowerShell 7.1。

【问题讨论】:

    标签: multithreading powershell scope powershell-core powershell-jobs


    【解决方案1】:

    您不能覆盖 $using: 变量引用 - 但您可以使用它来取消引用调用范围内的变量值,此时您可以对其进行变异(假设引用类型的值已分配给原始变量):

    $foo = @{ 
      Value = 1
    }
    Start-ThreadJob {
        Write-Host $using:foo
        $foo = $using:foo
        $foo.Value = 2
    } | Wait-Job | Out-Null
    
    Write-Host $foo.Value
    

    为确保线程同步,我建议您使用同步哈希表作为容器类型:

    $foo = [hashtable]::Synchronized(@{ 
      Value = 1
    })
    
    1..4 |%{Start-ThreadJob {
        Write-Host $using:foo
        $foo = $using:foo
        $foo.Value++
    }} | Wait-Job | Out-Null
    
    Write-Host $foo.Value
    

    此时您应该会看到5 的(4 倍递增)值

    【讨论】:

    • 感谢您的回答。对我知道那个。那么您认为我对“通过引用传递”“可能修改...变量” 的文档含义的理解是错误的吗?因为这不是我想象的“按引用传递”。这更像是传递一个指针按值
    • @MartinPrikryl 我肯定会说文档并不能很好地简洁地解释“如果您来自 C#/VB,则传递引用可能对您意味着其他东西。网”。我不确定我个人会如何表达它,但我鼓励你submit feedback on the PowerShell-Docs repo
    • 我已经按照您的建议提交了反馈:github.com/MicrosoftDocs/PowerShell-Docs/issues/7378
    • 顺便说一句,这个语法也有效:($using:foo).Value = 2
    猜你喜欢
    • 1970-01-01
    • 2014-09-19
    • 2023-01-22
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    相关资源
    最近更新 更多