Эксперимент передачи переменной в поток - PullRequest
1 голос
/ 23 января 2020

Я хочу понять, как потоки общаются друг с другом. Точнее, когда рождается новый поток и ему передается переменная, тогда это общая переменная или синхронизированная копия.

Вот что я делаю, чтобы выяснить это:

$A = '0'

# Expansion of the variable to 32 MB (2^25 characters)
(1..25).ForEach{ $A += $A -join '' }

$A
$A.Length

# Torment further. Writing a variable to a table
$B = [HashTable]::Synchronized(@{ Name = $A })

Clear-Variable A
Remove-Variable A

$B

Write-host "Oh, that wasn't easy. Owner, maybe enough?"

# But no, not enough. Now you pass B to another thread

$RunSpace = [Runspacefactory]::CreateRunspace()
$RunSpace.Open()
$RunSpace.SessionStateProxy.SetVariable('B', $B )
$PowerShell = [PowerShell]::Create().AddScript({})
$PowerShell.Runspace = $RunSpace

$Null = $PowerShell.BeginInvoke()

# Here I do not close the threads for clarity

Вот что я увидел на графике памяти:

enter image description here

Я понял, что использую синхронизированную копию хеш-таблицы $ B, а не одну таблицу , Но что, если таких больших таблиц много, а потоков много? Я безнадежно получаю полную трату памяти?

Действительно ли я вынужден создавать копии одной и той же хеш-таблицы $ B для каждого потока? Разве я не могу создать одну общую хеш-таблицу $ B для всех потоков?

Правка. Я решил поднять ставки и сделал 1..30 вместо 1..25 (от 2 до мощность 30, что составляет $ A GB 1 ГБ (!!!) ). И что я видел? Первый и второй шаги были добавлены 1 ГБ. То есть еще одна таблица 1 ГБ была передана в поток. В результате я получил 2 ГБ!

Просто посмотрите на это:

enter image description here

1 Ответ

1 голос
/ 23 января 2020

Я думаю, что это просто создает копию этой переменной:

$RunSpace.SessionStateProxy.SetVariable('B', $B )

Вам нужно передать ее как параметр. Ниже приведен пример

$LargeVar = [System.IO.File]::ReadAllBytes("C:\temp\SomeLargeFile.zip")

$work = { param($SharedVar)

   $threadId = [System.AppDomain]::GetCurrentThreadId()
   Write-Output "Thread $threadId : result $($SharedVar.count)"    
}

$workParams = @{SharedVar = $LargeVar}

$rs1 = [powershell]::Create()
$rs2 = [powershell]::Create()
$rs3 = [powershell]::Create()

foreach($rs in $rs1, $rs2, $rs3) {

   $rs.AddScript($work).AddParameters($workParams).Invoke()
   $rs.Commands.Clear() 

}

Если вы собираетесь параллельно запускать пространства выполнения, вам, вероятно, потребуется создать параллельный сбор и обмен данными между пространствами выполнения с его использованием.

...