我如何在Powershell中运行并行的foreach循环

时间:2019-02-21 14:04:39

标签: powershell

我正在尝试在Powershell Core中运行一些脚本(没有工作流程,没有ForEach的-Parallel选项)。

因此,我尝试将数组拆分为多个数组并并行运行。所以我这样做:

$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 :(得分:1)

使用临时变量来创建所需大小的数组,而不是在参数列表中评估范围运算符。然后将数组作为参数传递。像这样

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

编辑:-ArgumentList解散该数组,因此需要a bit trickery

通过打印有关传递的数组的详细信息来测试代码:

$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

答案 1 :(得分:0)

范围运算符“ ..”从字面上创建具有多个整数的数组。就像“” $ array + = element“一样,” 1 .. $ highnumber“会占用大量内存。for循环在工作中应该可以正常工作。您也永远不要使用$ iterCount。

还请注意,作业使用新流程。但是您可以在PS 6中使用start-threadjob代替线程。

#$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