2014-02-03 4 views
3

Все найденные мною утилиты используют предварительно определенное время сна для работы дроссельной заслонки. Мне нужно, чтобы дроссель подождал, пока работа не будет завершена, прежде чем начинать новую. Только 4 задания могут выполняться одновременно.Powershell Throttle Многопоточные задания через выполнение задания

Таким образом, сценарий будет работать до 4 и в настоящее время останавливается на 10 секунд, а затем запускает остальные. Я хочу, чтобы сценарий позволял запускать только 4 задания за один раз, и по завершении задания начинается новый.

Работы инициализируются через список имен серверов.

Можно ли это сохранить?

$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt" 

$scriptBlock = { #DO STUFF } 


$MaxThreads = 4 

foreach($server in $servers) { 
    Start-Job -ScriptBlock $scriptBlock -argumentlist $server 
    While($(Get-Job -State 'Running').Count -ge $MaxThreads) { 
      sleep 10 #Need this to wait until a job is complete and kick off a new one. 
    } 
} 
Get-Job | Wait-Job | Receive-Job 

ответ

4

Вы можете проверить следующее:

$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt" 
$scriptBlock = { #DO STUFF } 
invoke-command -computerName $servers -scriptblock $scriptBlock -jobname 'YourJobSpecificName' -throttlelimit 4 -AsJob 

Эта команда использует командлет Invoke-Command и его параметр AsJob для запуска фонового задания, которое выполняет ScriptBlock на многочисленных компьютерах. Поскольку команда не должна запускаться более 4 раз одновременно, команда использует параметр ThrottleLimit команды Invoke-Command, чтобы ограничить количество одновременных команд до 4.

Будьте осторожны, чтобы файл содержал имена компьютеров в домене.

4

Во избежание изобретательства колеса я бы рекомендовал использовать один из существующих инструментов .

Один из них - это сценарий Invoke-Parallel.ps1. Написано в PowerShell, вы можете увидеть, как оно реализовано напрямую. легко получить, и для его использования не требуется установка.

Другим является модуль SplitPipeline. Он может работать быстрее, потому что он написан на C#. Он также охватывает некоторые дополнительные случаи использования , например медленный или бесконечный ввод, использование сценариев инициализации и очистки.

В последнем случае код с 4-х параллельных трубопроводов будет

$servers | Split-Pipeline -Count 4 {process{ <# DO STUFF on $_ #> }} 
0

Ваш сценарий выглядит хорошо, попробуйте и добавить что-то вроде

Write-Host ("current count:" + ($(Get-Job -State 'Running').Count) + " on server:" + $server)

после цикла в то время как для работы, является ли количество заданий снижается там, где вы этого не ожидали.

2

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

http://www.get-blog.com/?p=189

Основная установка:

$ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault() 
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host) 
$RunspacePool.Open() 

$Code = [ScriptBlock]::Create($(Get-Content $FileName)) 
$PowershellThread = [powershell]::Create().AddScript($Code) 

$PowershellThread.RunspacePool = $RunspacePool 
$Handle = $PowershellThread.BeginInvoke() 
$Job = "" | Select-Object Handle, Thread, object 
$Job.Handle = $Handle 
$Job.Thread = $PowershellThread 
$Job.Object = $Object.ToString() 

$Job.Thread.EndInvoke($Job.Handle) 
$Job.Thread.Dispose() 
+0

Не плохая ссылка. Я предпочитаю также пробелы, так как они менее ресурсоемкими. – xXhRQ8sD2L7Z

1

Вместо sleep 10 вы также можете просто ждать на работу (-any работа):

Get-Job | Wait-Job -Any | Out-Null 

Когда больше не нужно начинать работу, начните печатать выходные данные. Вы также можете сделать это в цикле сразу после указанной выше команды. Сценарий будет получать задания по завершении, а не ждать до конца.

Get-Job -State Completed | % { 
    Receive-Job $_ -AutoRemoveJob -Wait 
} 

Так что ваш сценарий будет выглядеть следующим образом:

$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt" 

$scriptBlock = { #DO STUFF } 

$MaxThreads = 4 

foreach ($server in $servers) { 
    Start-Job -ScriptBlock $scriptBlock -argumentlist $server 
    While($(Get-Job -State Running).Count -ge $MaxThreads) { 
     Get-Job | Wait-Job -Any | Out-Null 
    } 
    Get-Job -State Completed | % { 
     Receive-Job $_ -AutoRemoveJob -Wait 
    } 
} 
While ($(Get-Job -State Running).Count -gt 0) { 
    Get-Job | Wait-Job -Any | Out-Null 
} 
Get-Job -State Completed | % { 
    Receive-Job $_ -AutoRemoveJob -Wait 
} 

Сказав все это, я предпочитаю (аналог пространства выполнения с Ryans поста) или даже рабочими процессы, если вы можете использовать их. Это гораздо менее ресурсоемкий процесс, чем запуск нескольких процессов powershell.

0

Я заметил, что все команды Start-Job в результате дополнительного conhost.exe процесса в диспетчере задач. Зная это, я был в состоянии задушить, используя следующую логику, где 5 мое требуемое количество одновременных потоков (поэтому я использую 4 в моем -gt заявления, так как я ищу отсчет больше):

while((Get-Process conhost -ErrorAction SilentlyContinue).Count -gt 4){Start-Sleep -Seconds 1} 
Смежные вопросы