Multithreading Powershell:来自多个线程的增量变量

Multithreading Powershell:来自多个线程的增量变量,multithreading,powershell,Multithreading,Powershell,在Powershell中,是否有一种方法可以安全地从多个线程中递增变量 我认为下面使用System.Threading.Interlock::Add的代码可以工作,但输出显示正在发生线程混搭 # Threads will attempt to increment this number $testNumber = 0 # Script will increment the test number 10 times $script = { Param( [ref]$te

在Powershell中,是否有一种方法可以安全地从多个线程中递增变量

我认为下面使用
System.Threading.Interlock::Add
的代码可以工作,但输出显示正在发生线程混搭

# Threads will attempt to increment this number
$testNumber = 0

# Script will increment the test number 10 times
$script =  {
    Param(
        [ref]$testNumber
    )
    1..10 | % {
        [System.Threading.Interlocked]::Add($testNumber, 1) | Out-Null
    }
}

#  Start 10 threads to increment the same number
$threads = @()
1..10 | % {
    $ps = [powershell]::Create()
    $ps.AddScript($script) | Out-Null
    $ps.RunspacePool = $pool
    $ps.AddParameter('testNumber', [ref]$testNumber) | Out-Null
    
    $threads += @{
        ps = $ps
        handle = $ps.BeginInvoke()
    }
}

# Wait for threads to complete
while ($threads | ? {!$_.Handle.IsCompleted }) {
    Start-Sleep -Milliseconds 100
}

# Print the output (should be 100=10*10, but is between 90 and 100)
echo $testNumber
正如在注释中一样,您需要使用同步哈希表跨运行空间边界读写数据(请参阅内联注释以获取解释):


我请求您需要创建一个同步哈希表,例如:
[hashtable]::synchronized(@{TestNumber=0})
,请参阅例如:
$pool
是未定义的变量。复制粘贴错误?
# Threads will attempt to increment this number
$testNumber = 0

# Create synchronized hashtable to act as gatekeeper
$syncHash = [hashtable]::Synchronized(@{ testNumber = $testNumber })

# Create runspace pool with a proxy variable mapping back to $syncHash
$iss = [initialsessionstate]::CreateDefault2()
$iss.Variables.Add(
  [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('syncHash', $syncHash,'')
)
$pool = [runspacefactory]::CreateRunspacePool($iss)
$pool.Open()

# Script will increment the test number 10 times
$script =  {
    Param(
        [string]$targetValue
    )
    1..10 | % {
        # We no longer need Interlocked.* and hairy [ref]-casts, $syncHash is already thread safe
        $syncHash[$targetValue]++ 
    }
}

#  Start 10 threads to increment the same number
$threads = @()
1..10 | % {
    $ps = [powershell]::Create()
    $ps.AddScript($script) | Out-Null
    $ps.RunspacePool = $pool

    # We're no longer passing a [ref] to the variable in the calling runspace.
    # Instead, we target the syncHash entry by name
    $ps.AddParameter('targetValue', 'testNumber') | Out-Null
    
    $threads += @{
        ps = $ps
        handle = $ps.BeginInvoke()
    }
}

# Wait for threads to complete
while ($threads | ? {!$_.Handle.IsCompleted }) {
    Start-Sleep -Milliseconds 100
}

$errorCount = 0
# End invocation lifecycle
$threads|%{
  if($_.ps.HadErrors){
    $errorCount++
  }
  $_.ps.EndInvoke($_.handle)
}

if($errorCount){
  Write-Warning "${errorCount} thread$(if($errorCount -gt 1){'s'}) had errors"
}

# Et voila, $syncHash['testNumber'] is now 100
$syncHash['testNumber']