Почему пропадает переменная после одного раза использования в PowerShell в командлете Start-ThreadJob?
Пишу
Start-ThreadJob -ThrottleLimit 500 -InputObject $for_list_pc -ScriptBlock { }
Внутри scriptblok согласно документации использую $input для доступа к переменной переданной через -InputObject $for_list_pc. Но при втором вызове $input там ничего нет. Что я делаю не так?
$input это системная переменная и она автоматически очищается по завершению блока работы.
Подробнее почитать о ней вы можете в справке командой Get-Help about_Automatic_Variables
Павел, Прошу прощения за задержку с ответом.
Времени не было толком разобраться с этим вопросом))
Суть в следующем, переменная $input системная и временная и содержит в себе массив данных. По своей сути она похожа на переменную $_ которая используется при обработке каждого элемента массива и очищается сразу же после передачи элемента, так же работает и $input, но она передает весь массив целиком и сразу очищается.
Обратиться к ней несколько раз не получится, но есть вариант загнать ее значение в какую-либо созданную нами переменную и в дальнейшем уже использовать ее.
Простенький пример ниже:
Евгений, Благодарю, пробовал $data= $input, не работало, не знаю как устроен ps, видимо создавалась ссылка на $input, которая после этого ни на что не вела. Не знал про "= @".
Не надо вводить в заблуждение. Никакие переменные в Powershell cами не очищаются.
Просто переменная $Input - это поток. И если читать из потока, то данные в нём, конечно, могут кончиться.
Читаем в цикле - всё на месте
PS D:\> $for_list_pc= 1,2,3,4,5,36
PS D:\> $for_list_pc | Start-ThreadJob -ThrottleLimit 500 -ScriptBlock {
>> "Stream here:"; gm -input $input
>> foreach($i in $input) { " This is input - " + $i }
>> } |
>> Wait-Job | Receive-Job
Stream here:
TypeName: System.Management.Automation.Runspaces.PipelineReader`1+<GetReadEnumerator>d__20[[System.Object, mscorlib, Version=4.0.0.0, Cu
lture=neutral, PublicKeyToken=b77a5c561934e089]]
Name MemberType Definition
---- ---------- ----------
Dispose Method void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
MoveNext Method bool IEnumerator.MoveNext()
Reset Method void IEnumerator.Reset()
ToString Method string ToString()
<>4__this Property System.Management.Automation.Runspaces.PipelineReader[System.Object] <>4__this {get;set;}
Current Property System.Object Current {get;}
This is input - 1
This is input - 2
This is input - 3
This is input - 4
This is input - 5
This is input - 36
btw, для передачи параметров внутрь Job давно уже выдуман гораздо более изящный способ - using:
PS D:\> Start-ThreadJob -ThrottleLimit 500 -ScriptBlock {
>> foreach($i in $using:for_list_pc) { "This is input - " + $i }
>> } |
>> Wait-Job | Receive-Job
This is input - 1
This is input - 2
This is input - 3
This is input - 4
This is input - 5
This is input - 36
И, если ожидалось параллельное исполнение scriptblock, то всё должно выглядеть как-то так:
$for_list_pc | Foreach-Object { $_ | Start-ThreadJob -ThrottleLimit 500 -ScriptBlock {
" This is input - " + $input
} } |
Wait-Job | Receive-Job
This is input - 1
This is input - 2
This is input - 3
This is input - 4
This is input - 5
This is input - 36
этот код создаст $for_list_pc.Count потоков, которые будут выполняться параллельно по 500 штук за раз