【问题标题】:How do I run parallel foreach loop?如何运行并行 foreach 循环?
【发布时间】:2019-07-15 11:24:09
【问题描述】:

我正在尝试在 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) 作为解决方法,但我不确定这是否是我能做的最好的。

【问题讨论】:

标签: powershell


【解决方案1】:

范围运算符“..”实际上创建了一个包含那么多整数的数组。就像 ""$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

【讨论】:

    【解决方案2】:

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

    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
    

    【讨论】:

    • 我试过了,但它不起作用:只执行一次迭代
    • @AlexZhukovskiy 糟糕,忘记了参数 unravel。查看修改后的版本。
    猜你喜欢
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 2023-03-29
    • 1970-01-01
    • 2016-05-27
    • 2013-11-28
    相关资源
    最近更新 更多