Может ли PowerShell запускать команды параллельно?
У меня есть powershell script, чтобы выполнить пакетную обработку на кучу изображений, и я бы хотел сделать некоторую параллельную обработку. У Powershell, по-видимому, есть некоторые варианты обработки фона, такие как start-job, wait-job и т.д., Но единственный хороший ресурс, который я нашел для выполнения параллельной работы, заключался в написании текста script и его запуске (Многопоточность PowerShell)
В идеале, я хотел бы что-то похожее на параллельное foreach в .net 4.
Что-то довольно похоже:
foreach-parallel -threads 4 ($file in (Get-ChildItem $dir))
{
.. Do Work
}
Может быть, мне лучше спуститься до С#...
Ответы
Ответ 1
Вы можете выполнять параллельные задания в Powershell 2, используя фоновые задания. Проверьте Start-Job и другие командлеты задания.
# Loop through the server list
Get-Content "ServerList.txt" | %{
# Define what each job does
$ScriptBlock = {
param($pipelinePassIn)
Test-Path "\\$pipelinePassIn\c'$\Something"
Start-Sleep 60
}
# Execute the jobs in parallel
Start-Job $ScriptBlock -ArgumentList $_
}
Get-Job
# Wait for it all to complete
While (Get-Job -State "Running")
{
Start-Sleep 10
}
# Getting the information back from the jobs
Get-Job | Receive-Job
Ответ 2
Ответ от Стива Таунсенда правилен в теории, но не на практике, как отметил @likwid. В моем обновленном коде учитывается бартер условий работы - ничто не пересекает этот барьер по умолчанию! Таким образом, автоматическая переменная $_
может использоваться в цикле, но не может использоваться непосредственно в блоке script, потому что она находится внутри отдельного контекста, созданного заданием.
Чтобы передать переменные из родительского контекста в дочерний контекст, используйте параметр -ArgumentList
на Start-Job
для его отправки и используйте param
внутри блока script для его получения.
cls
# Send in two root directory names, one that exists and one that does not.
# Should then get a "True" and a "False" result out the end.
"temp", "foo" | %{
$ScriptBlock = {
# accept the loop variable across the job-context barrier
param($name)
# Show the loop variable has made it through!
Write-Host "[processing '$name' inside the job]"
# Execute a command
Test-Path "\$name"
# Just wait for a bit...
Start-Sleep 5
}
# Show the loop variable here is correct
Write-Host "processing $_..."
# pass the loop variable across the job-context barrier
Start-Job $ScriptBlock -ArgumentList $_
}
# Wait for all to complete
While (Get-Job -State "Running") { Start-Sleep 2 }
# Display output from all jobs
Get-Job | Receive-Job
# Cleanup
Remove-Job *
(Я вообще-то хотел бы предоставить ссылку на документацию PowerShell в качестве подтверждающего доказательства, но, увы, мой поиск был бесплодным. Если вам известно, где документировано разделение контекста, отправьте комментарий здесь, чтобы сообщить мне!)
Ответ 3
http://gallery.technet.microsoft.com/scriptcenter/Invoke-Async-Allows-you-to-83b0c9f0
i создал invoke-async, который позволяет вам запускать несколько script блоков/командлетов/функций одновременно. это отлично подходит для небольших заданий (сканирование подсетей или запрос wmi на 100 машин), потому что накладные расходы на создание рабочей области и время запуска старта - это довольно радикально. Его можно использовать так.
с помощью скриптового блока,
$sb = [scriptblock] {param($system) gwmi win32_operatingsystem -ComputerName $system | select csname,caption}
$servers = Get-Content servers.txt
$rtn = Invoke-Async -Set $server -SetParam system -ScriptBlock $sb
просто командлет/функция
$servers = Get-Content servers.txt
$rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50
Ответ 4
Фоновые задания дороги в настройке и не подлежат повторному использованию. PowerShell MVP Ойсин Грехан
имеет хороший пример многопоточности PowerShell.
(25.10.2010 сайт не работает, но доступен через веб-архив).
Я использовал адаптированный скрипт Oisin для использования в подпрограмме загрузки данных здесь:
http://rsdd.codeplex.com/SourceControl/changeset/view/a6cd657ea2be#Invoke-RSDDThreaded.ps1
Ответ 5
Чтобы завершить предыдущие ответы, вы также можете использовать Wait-Job
для ожидания завершения всех заданий:
For ($i=1; $i -le 3; $i++) {
$ScriptBlock = {
Param (
[string] [Parameter(Mandatory=$true)] $increment
)
Write-Host $increment
}
Start-Job $ScriptBlock -ArgumentList $i
}
Get-Job | Wait-Job | Receive-Job
Ответ 6
Там очень много ответов на это в эти дни:
- задания (или рабочие задания в PS 6 или модуле)
- запуск процесса
- Рабочие процессы
- API PowerShell с другим пространством выполнения
- команда invoke с несколькими компьютерами, которые могут быть локальными (должны быть администраторами)
- несколько вкладок сессии в ise
Вот рабочие процессы с буквально foreach -parallel:
workflow work {
foreach -parallel ($i in 1..3) {
sleep 5
"$i done"
}
}
work
3 done
1 done
2 done
Или рабочий процесс с параллельным блоком:
function sleepfor($time) { sleep $time; "sleepfor $time done"}
workflow work {
parallel {
sleepfor 3
sleepfor 2
sleepfor 1
}
'hi'
}
work
sleepfor 1 done
sleepfor 2 done
sleepfor 3 done
hi
Вот пример API с runspaces:
$a = [PowerShell]::Create().AddScript{sleep 5;'a done'}
$b = [PowerShell]::Create().AddScript{sleep 5;'b done'}
$c = [PowerShell]::Create().AddScript{sleep 5;'c done'}
$r1,$r2,$r3 = ($a,$b,$c).begininvoke() # run in background
$a.EndInvoke($r1); $b.EndInvoke($r2); $c.EndInvoke($r3) # wait
($a,$b,$c).streams.error # check for errors
($a,$b,$c).dispose() # clean
a done
b done
c done