Как запустить параллельный цикл foreach? - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь запустить какой-нибудь скрипт в Powershell Core (без рабочего процесса, без опции -Parallel для ForEach).

Поэтому я пытаюсь разбить мой массив на партии и запустить их параллельно.Итак, я делаю:

$iterCount = 150000;
$threadCount = 8;
$batchSize = $iterCount/$threadCount;

$block = {
    Param($range)

    Foreach ($i in $range) {
        ...
    }
}

For ($i = 0; $i -lt 150000; $i += $batchSize) {
    Start-Job -Scriptblock $block -ArgumentList $i..$i+$batchSize
}

Но когда я звоню, я получаю

Start-Job : Cannot bind parameter 'InitializationScript'. Cannot convert the "..                                        0+18750" value of type "System.String" to type "System.Management.Automation.Scr                                        iptBlock".
At /home/tchain/dit/push_messages3.ps1:63 char:48
+     Start-Job -Scriptblock $block -ArgumentList $i..$i+$batchSize
+                                                   ~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [Start-Job], ParameterBindingExce                                        ption
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Co                                        mmands.StartJobCommand

Кажется, что ArgumentList все строковое, поэтому я не могу передать диапазон.

Есть ли способ пройти строго типизированный диапазон?Есть ли лучший способ распараллелить цикл?Я хотел бы написать (0..150000).AsParallel().ForEach($i => ...) Но похоже, что я не могу.

Я сделал Param([int] $from, [int] $to) в качестве обходного пути, но я не уверен, что это лучшее, что я могу сделать.

Ответы [ 2 ]

0 голосов
/ 28 июля 2019

Оператор диапазона ".." буквально создает массив из такого количества целых чисел.Точно так же, как "" $ array + = element "," 1 .. $ highnumber "может использовать много памяти. Цикл for должен нормально работать в работе. Вы также никогда не должны использовать $ iterCount.

Также обратите вниманиечто задания используют новые процессы. Но вы можете использовать start-threadjob вместо этого в PS 6, чтобы использовать потоки.

#$iterCount = 150000;                                                                                                                                 
$iterCount = 24
$threadCount = 8;
$batchSize = $iterCount/$threadCount;

$block = {
    Param($start,$range)
    "start $start range $range"
    For ($i = $start; $i -lt $range; $i++) {
        $i 
    }
}

For ($i = 0; $i -lt $iterCount; $i += $batchSize) {
    Start-Job -Scriptblock $block -ArgumentList $i,($i+$batchSize)
}


start 0 range 3
0
1
2
start 3 range 6
3
4
5
start 6 range 9
6
7
8
start 9 range 12
9
10
11
start 12 range 15
12
13
14
start 15 range 18
15
16
17
start 18 range 21
18
19
20
start 21 range 24
21
22
23

В целях сравнения фактически создайте диапазон ".." в блоке скриптов.приемная работа может появиться не в порядке.

$iterCount = 150000                                                                   
$threadCount = 8
$batchSize = $iterCount/$threadCount

$block = {
    Param($start,$range)
    "start $start range $range"                                      
    Foreach ($i in $start..($range-1)) {
        # $i                                                                          
    }
}

For ($i = 0; $i -lt $iterCount; $i += $batchSize) {
    Start-Job -Scriptblock $block -ArgumentList $i,($i+$batchSize)
}


start 0 range 18750
start 18750 range 37500
start 75000 range 93750
start 131250 range 150000
start 93750 range 112500
start 37500 range 56250
start 56250 range 75000
start 112500 range 131250
0 голосов
/ 21 февраля 2019

Вместо оценки оператора диапазона в списке аргументов используйте временные переменные для создания массива нужного размера.Затем передайте массив в качестве аргумента.Точно так же,

For ($i = 0; $i -lt 150000; $i += $batchSize) {
    $j = $i+$batchSize
    $range = $i..$j
    Start-Job -Scriptblock $block -ArgumentList (,$range)
}

Редактировать: -ArgumentList распутывает массив, поэтому требуется небольшая хитрость .

Проверка кода путем печати сведений о переданном массиве:

$block = {
  Param([array]$range)
  write-host "len`t[0]`t[-1]"
  write-host $range.length"`t"$range[0]"`t"$range[-1]
}

For ($i = 0; $i -lt 150000; $i += $batchSize) {
    $j = $i+$batchSize
    $range = $i..$j
    Start-Job -Scriptblock $block -ArgumentList (,$range)
}

get-job | receive-job
len     [0]     [-1]
18751    0       18750
len     [0]     [-1]
18751    18750   37500
len     [0]     [-1]
18751    37500   56250
len     [0]     [-1]
18751    56250   75000
len     [0]     [-1]
18751    75000   93750
len     [0]     [-1]
18751    93750   112500
len     [0]     [-1]
18751    112500          131250
len     [0]     [-1]
18751    131250          150000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...