7

我想使用 Powershell 尽快填充具有相同整数值的动态数组。
Measure-Command 显示我的系统需要 7 秒才能将其填满。
我当前的代码(剪断)看起来像:

$myArray = @()
$length = 16385
for ($i=1;$i -le $length; $i++) {$myArray += 2}  

(完整代码可以在gist.github.comsuperuser上看到)

考虑$length可以改变。但为了更好地理解,我选择了固定长度。

问:如何加速这个 Powershell 代码?

4

5 回答 5

19

你可以重复数组,就像你可以对字符串做的那样:

$myArray = ,2 * $length

这意味着»获取具有单个元素的数组2并重复$length多次,产生一个新数组。«。

请注意,您不能真正使用它来创建多维数组,因为以下原因:

$some2darray = ,(,2 * 1000) * 1000

只会创建对内部数组的 1000 个引用,使它们对操作毫无用处。在这种情况下,您可以使用混合策略。我用过

$some2darray = 1..1000 | ForEach-Object { ,(,2 * 1000) }

过去,但低于性能测量表明

$some2darray = foreach ($i in 1..1000) { ,(,2 * 1000) }

将是一种更快的方式。


一些性能测量:

Command                                                  Average Time (ms)
-------                                                  -----------------
$a = ,2 * $length                                                 0,135902 # my own
[int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length)           7,15362 # JPBlanc
$a = foreach ($i in 1..$length) { 2 }                             14,54417
[int[]]$a = -split "2 " * $length                                24,867394
$a = for ($i = 0; $i -lt $length; $i++) { 2 }                    45,771122 # Ansgar
$a = 1..$length | %{ 2 }                                         431,70304 # JPBlanc
$a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 }       10425,79214 # original code

通过运行每个变体 50 次Measure-Command,每个变体都具有相同的 值$length,并对结果进行平均。

实际上,位置 3 和 4 有点出人意料。foreach显然,超过一个范围而不是使用普通for循环要好得多。


生成上图的代码:

$length = 16384

$tests = '$a = ,2 * $length',
         '[int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length)',
         '$a = for ($i = 0; $i -lt $length; $i++) { 2 }',
         '$a = foreach ($i in 1..$length) { 2 }',
         '$a = 1..$length | %{ 2 }',
         '$a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 }',
         '[int[]]$a = -split "2 " * $length'

$tests | ForEach-Object {
    $cmd = $_
    $timings = 1..50 | ForEach-Object {
        Remove-Variable i,a -ErrorAction Ignore
        [GC]::Collect()
        Measure-Command { Invoke-Expression $cmd }
    }
    [pscustomobject]@{
        Command = $cmd
        'Average Time (ms)' = ($timings | Measure-Object -Average TotalMilliseconds).Average
    }
} | Sort-Object Ave* | Format-Table -AutoSize -Wrap
于 2013-07-26T09:09:10.807 回答
6

避免在循环中附加到数组。它在每次迭代时将现有数组复制到一个新数组。改为这样做:

$MyArray = for ($i=1; $i -le $length; $i++) { 2 }
于 2013-07-26T08:35:16.887 回答
5

使用 PowerShell 3.0,您可以使用(需要 .NET Framework 3.5 或更高版本):

[int[]]$MyArray = ([System.Linq.Enumerable]::Repeat(2, 65000))

使用 PowerShell 2.0

$AnArray = 1..65000 | % {2}
于 2013-07-26T09:04:03.977 回答
1

目前尚不清楚您在尝试什么。我试着看你的代码。但是,$myArray +=2意味着您只是添加 2 作为元素。例如,这是我的测试代码的输出:

$myArray = @()
$length = 4
for ($i=1;$i -le $length; $i++) {
    Write-Host $myArray
    $myArray += 2
}

2
2 2
2 2 2

为什么需要多次添加 2 作为数组元素?

如果你想要的只是填充相同的值,试试这个:

$myArray = 1..$length | % { 2 }
于 2013-07-26T08:03:01.100 回答
-1

如果你真的需要它,那么就使用 ArrayLists 和 Tuples:

$myArray = New-Object 'Collections.ArrayList'
$myArray = foreach($i in 1..$length) {
    [tuple]::create(2)
}

如果您需要稍后对其进行排序,请使用它(通常会慢一点):

$myArray = New-Object 'Collections.ArrayList'
foreach($i in 1..$length) {
    $myArray.add(
        [tuple]::create(2)
    )
}

两个版本对我来说都在 20 毫秒范围内;-)

于 2018-10-22T07:21:04.663 回答