Использует ли параллельный foreach powershell не более 5 потоков?

Параметр throttlelimit функции foreach -parallel может управлять количеством процессов, используемых при выполнении скрипта. Но у меня не может быть более 5 процессов, даже если я установил throttlelimit больше 5.

Скрипт выполняется в нескольких процессах powershell. Поэтому я проверяю PID внутри скрипта. А затем сгруппируйте PID, чтобы я мог знать, сколько процессов используется для выполнения скрипта.

function GetPID() {
    $PID
}

workflow TestWorkflow {
    param($throttlelimit)
    foreach -parallel -throttlelimit $throttlelimit ($i in 1..100) {
        GetPID
    }
}

foreach ($i in 1..8) {
    $pids = TestWorkflow -throttlelimit $i
    $measure = $pids | group | Measure-Object
    $measure.Count
}

Выход

1
2
3
4
5
5
5
5

Для $i меньше или равно 5 у меня $i процессов. Но для $i больше 5 у меня есть только 5 процессов. Есть ли способ увеличить количество процессов при выполнении скрипта?

Изменить: в ответ на ответ @SomeShinyObject я добавил еще один тестовый пример. Это модификация примера, приведенного @SomeShinyObject. Я добавил функцию S, которая ничего не делает, кроме сна на 10 секунд.

function S($n) {
    $s = Get-Date
    $s.ToString("HH:mm:ss.ffff") + " start sleep " + $n
    sleep 10
    $e = Get-Date
    $e.ToString("HH:mm:ss.ffff") + " end sleep " + $n + " diff " + (($e-$s).TotalMilliseconds)
}

Workflow Throttle-Me {
    [cmdletbinding()]
    param (
        [int]$ThrottleLimit = 10,
        [int]$CollectionLimit = 10
    )

    foreach -parallel -throttlelimit $ThrottleLimit ($n in 1..$CollectionLimit){
        $s = Get-Date
        $s.ToString("HH:mm:ss.ffff") + " start " + $n
        S $n
        $e = Get-Date
        $e.ToString("HH:mm:ss.ffff") + " end " + $n + " diff " + (($e-$s).TotalMilliseconds)
    }
}

Throttle-Me -ThrottleLimit 10 -CollectionLimit 20

И вот вывод. Я сгруппировал вывод по времени (количество секунд) и немного изменил порядок внутри каждой группы, чтобы сделать его более понятным. Совершенно очевидно, что функция S вызывается 5 на 5, хотя я установил throttlelimit в 10 (сначала у нас есть start sleep 6..10, через 10 секунд у нас есть start sleep 1..5, и через 10 секунд start sleep 11..15, и через 10 секунд start sleep 16..20).

03:40:29.7147 start 10
03:40:29.7304 start 9
03:40:29.7304 start 8
03:40:29.7459 start 7
03:40:29.7459 start 6
03:40:29.7616 start 5
03:40:29.7772 start 4
03:40:29.7772 start 3
03:40:29.7928 start 2
03:40:29.7928 start 1

03:40:35.3067 start sleep 7
03:40:35.3067 start sleep 8
03:40:35.3067 start sleep 9
03:40:35.3692 start sleep 10
03:40:35.4629 start sleep 6

03:40:45.3292 end sleep 7 diff 10022.5353
03:40:45.3292 end sleep 8 diff 10022.5353
03:40:45.3292 end sleep 9 diff 10022.5353
03:40:45.3761 end sleep 10 diff 10006.8765
03:40:45.4855 end sleep 6 diff 10022.5243
03:40:45.3605 end 9 diff 15630.1005
03:40:45.3917 end 7 diff 15645.7465
03:40:45.3917 end 8 diff 15661.3313
03:40:45.4229 end 10 diff 15708.2274
03:40:45.5323 end 6 diff 15786.3969
03:40:45.4386 start sleep 5
03:40:45.4542 start sleep 4
03:40:45.4542 start sleep 3
03:40:45.4698 start sleep 2
03:40:45.5636 start sleep 1
03:40:45.4698 start 11
03:40:45.4855 start 12
03:40:45.5011 start 13
03:40:45.5167 start 14
03:40:45.6105 start 15

03:40:55.4596 end sleep 3 diff 10005.4374
03:40:55.4596 end sleep 4 diff 10005.4374
03:40:55.4596 end sleep 5 diff 10021.0426
03:40:55.4752 end sleep 2 diff 10005.3992
03:40:55.5690 end sleep 1 diff 10005.3784
03:40:55.4752 end 3 diff 25698.0221
03:40:55.4909 end 5 diff 25729.302
03:40:55.5065 end 4 diff 25729.2523
03:40:55.5221 end 2 diff 25729.2559
03:40:55.6159 end 1 diff 25823.032
03:40:55.5534 start sleep 11
03:40:55.5534 start sleep 12
03:40:55.5690 start sleep 13
03:40:55.5846 start sleep 14
03:40:55.6784 start sleep 15
03:40:55.6002 start 16
03:40:55.6002 start 17
03:40:55.6159 start 18
03:40:55.6326 start 19
03:40:55.7096 start 20

03:41:05.5692 end sleep 11 diff 10015.8226
03:41:05.5692 end sleep 12 diff 10015.8226
03:41:05.5848 end sleep 13 diff 10015.8108
03:41:05.6004 end sleep 14 diff 10015.8128
03:41:05.6942 end sleep 15 diff 10015.8205
03:41:05.5848 end 12 diff 20099.3218
03:41:05.6004 end 11 diff 20130.5719
03:41:05.6161 end 13 diff 20114.9729
03:41:05.6473 end 14 diff 20130.5962
03:41:05.6942 end 15 diff 20083.7506
03:41:05.6317 start sleep 17
03:41:05.6317 start sleep 16
03:41:05.6473 start sleep 18
03:41:05.6629 start sleep 19
03:41:05.7411 start sleep 20

03:41:15.6320 end sleep 16 diff 10000.3608
03:41:15.6320 end sleep 17 diff 10000.3608
03:41:15.6477 end sleep 18 diff 10000.3727
03:41:15.6633 end sleep 19 diff 10000.3709
03:41:15.7414 end sleep 20 diff 10000.3546
03:41:15.6477 end 16 diff 20047.4375
03:41:15.6477 end 17 diff 20047.4375
03:41:15.6633 end 18 diff 20047.4295
03:41:15.7101 end 19 diff 20077.5169
03:41:15.7414 end 20 diff 20031.7909

person Haoshu    schedule 27.04.2017    source источник
comment
В качестве отступления: рабочие процессы Windows PowerShell были представлены в версии 3, но так и не получили широкого распространения. Учитывая, что они больше не доступен в PowerShell (Core) v6+, куда будут направлены все будущие усилия по разработке, я думаю, будет справедливо назвать эту технологию устаревшей.   -  person mklement0    schedule 05.06.2021


Ответы (2)


Я считаю, что ваш тест немного некорректен. Согласно этой статье TechNet, $PID не является доступной переменной в рабочем процессе сценария.

Лучший тест с объяснением можно найти на этом сайт

По сути, ThrottleLimit устанавливается на теоретическое [Int32]::MaxValue. Плакат разработал лучший тест для проверки параллельной обработки (слегка измененный):

Workflow Throttle-Me {
    [cmdletbinding()]
    param (
        [int]$ThrottleLimit = 10,
        [int]$CollectionLimit = 10
    )

    foreach -parallel -throttlelimit $ThrottleLimit ($n in 1..$CollectionLimit){
        "Working on $n"
        "{0:hh}:{0:mm}:{0:ss}" -f (Get-Date)
    }
}
person SomeShinyObject    schedule 27.04.2017
comment
Я внес небольшую модификацию в ваш пример и поместил ее в свой вопрос. Я добавил функцию в середине двух ваших строковых выходных данных. Кажется, что независимо от того, как я throttlelimit установлен, функция вызывается 5 на 5. Я также добавил некоторые пояснения к моему вопросу. - person Haoshu; 27.04.2017
comment
Я вижу такое же поведение, когда вызываю функцию из моего параллельного блока foreach. Предел дроссельной заслонки фактически ограничен 5. Очень странно. - person Matt Varblow; 12.01.2018

Я не могу говорить об этом конкретном командлете, но, как вы обнаружили, PowerShell использует только один поток для каждого PID. Общие способы обойти это: PSJobs. и Пространства выполнения. Runspaces сложнее, чем PSJob, но они также имеют значительно лучшую производительность, что делает их популярным выбором. Недостатком является то, что весь ваш код должен решаться вокруг них, что в большинстве случаев означает полное переписывание.

К сожалению, как бы Microsoft ни продвигала PowerShell, он создан не для производительности и скорости. Но он работает настолько хорошо, насколько это возможно, будучи привязанным к .NET.

person Michael Timmerman    schedule 27.04.2017
comment
Это относится к рабочим процессам PowerShell, которые допускают параллельную обработку. (blogs.technet.microsoft.com/ heyscriptingguy/2012/12/26/) - person SomeShinyObject; 27.04.2017