Недавно передо мной встала задача получения результатов выполнения некоторой команды на нескольких тысячах хостов. Т.к. выполнение команды занимает некоторое время, логичным способом ускорения процесса будет параллельный запуск нескольких команд одновременно. В случае PowerShell, для этого у нас есть прекрасный инструмент Background Jobs.
Однако ресурсы компьютера, где я запускал все эти задания, ограничены и он не выдерживал одновременной работы более 100 заданий. К сожалению, в PowerShell пока не встроено никакого способа ограничения количества одновременно выполняющихся заданий, равно как и очереди для них.
Я не первый, кто столкнулся с такой проблемой: официальный блог Hey, Scripting Guy! предлагает способ организации очереди, с использованием объектов .NET Framework. Признаюсь, честно, у меня не получилось заставить этот метод работать и, в итоге, я сообразил, что очередь заданий можно организовать гораздо проще, всё что нужно, это:
- Цикл
- Проверка на кол-во текущих работающих заданий
- Переменная, разрешающая отправку следующего задания на выполнение
Получилась вот такая обёртка, реализующая эти три условия:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$maxConcurrentJobs = 100 #Максимальное количество одновременно выполняющихся заданий. foreach($Object in $Objects) { #$Objects — коллекция объектов для обработки. Например, список компьютеров. $Check = $false #Переменная, помогающая выйти из бесконечного цикла ожидания, как только кол-во одновременно работающих заданий станет меньше чем $maxConcurrentJobs. while ($Check -eq $false) { if ((Get-Job -State 'Running').Count -lt $maxConcurrentJobs) { $ScriptBlock = { #Сюда вставьте код своего задания. } Start-Job -ScriptBlock $ScriptBlock $Check = $true #После отправки задания на выполнение, выходим из бесконечного цикла и переходим к следующему элементу из $Objects. } } } |
Мой вариант чрезвычайно похож на решение (которое я нашёл, как обычно, уже ПОСЛЕ того, как придумал свой вариант), предложенное в комментарии на StackOverflow, но, как там и заметили, в варианте, предложенном на SO, есть вероятность пропуска некоторых элементов для обработки.
Как показало исследование Бо Прокса, фоновые задания PowerShell проигрывают в скорости выполнения раздельным средам исполнения (runspaces). Как использовать несколько сред исполнения, Бо подробно рассказывает в своём блоге.