Arrays Powershell—创建非常大的哈希表数组的最快方法

Arrays Powershell—创建非常大的哈希表数组的最快方法,arrays,performance,powershell,optimization,hashtable,Arrays,Performance,Powershell,Optimization,Hashtable,我试图创建一个相当大的哈希表数组,其中大部分数据要么完全随机,要么从列表中随机选取 这是我的当前代码 $ArrayData=@() $ArrayDataRows=150000 foreach($i在1..$ArrayDataRows中){ $thisobject=[PSCustomObject]@{ 数字=$i 地点=获取随机-输入对象NJ、UT、NY、MI、PA、FL、AL、NM、CA、OK、TX、CO、AZ 颜色=获取随机-输入对象红色、黄色、蓝色、紫色、绿色、白色、黑色 区域=(获取随机-

我试图创建一个相当大的哈希表数组,其中大部分数据要么完全随机,要么从列表中随机选取

这是我的当前代码

$ArrayData=@()
$ArrayDataRows=150000
foreach($i在1..$ArrayDataRows中){
$thisobject=[PSCustomObject]@{
数字=$i
地点=获取随机-输入对象NJ、UT、NY、MI、PA、FL、AL、NM、CA、OK、TX、CO、AZ
颜色=获取随机-输入对象红色、黄色、蓝色、紫色、绿色、白色、黑色
区域=(获取随机-InputObject$([char[]](65..90))-计数10)-加入“”
组=获取随机-输入对象@(1..20)
}
$ArrayData+=$thisobject
}
但我注意到,它似乎没有效率。总共需要25分钟才能完成15万排

我在这里没有发布一些额外的代码,这些代码测量了每个实例所用的时间,并估计了从它到它的前辈的平均时间。最初,我估计总数为450秒,前3k个项目的每个实例的平均值为0.002秒,但后来它只是缓慢地爬行到0.016秒或平均值的8倍

如何在获得相同数据的同时优化和/或提高效率?

[编辑-您不是在创建哈希表数组。您是在创建
PSCustomObject
项数组。[*grin*]]

标准阵列是一个固定大小的对象。查看
$ArrayData.IsFixedSize
以确认这一点。[咧嘴笑]

因此,当您在标准阵列上使用
+=
时,powershell会创建一个新的、一项较大的阵列,将旧阵列复制到新阵列中,最后添加新项目。当物品数量和大小为“小”时,速度很快,但随着数量/大小的增加,速度会变慢[越来越慢,越来越慢]

有两种常见的解决方案

  • 使用具有
    .Add()
    方法的集合类型
    人们通常使用
    ArrayList
    [deprecated]和
    Generic.List
    。当您添加到第1个时,它会输出一个索引号,因此即使它没有被弃用,我也不会使用它。[咧嘴笑]
  • 使用输出流
    您可以使用
    $Results=foreach($Collection中的Thing){Do Stuff}
    ,脚本块的输出将保存在RAM中,直到循环完成。然后它将一次全部填充到
    $Results
    集合中
第二个是最快的

如果在构建集合后不需要更改集合的大小,则使用第二种方法。否则使用第1个

作为速度的一个例子,您的代码[包含15000项]在我的系统上以39秒的时间运行。使用“发送到输出”技术需要24秒

请记住,当阵列变大时,速度会继续变慢。我不愿意等待150k迭代

这是我的演示代码

$ArrayDataRows = 15e3
$PlaceList = 'NJ, UT, NY, MI, PA, FL, AL, NM, CA, OK, TX, CO, AZ'.Split(',').Trim()
$ColorList = 'red, yellow, blue, purple, green, white, black'.Split(',').Trim()
$UC_LetterList = [char[]](65..90)
$GroupList = 1..20

(Measure-Command -Expression {
    $ArrayData = foreach ($i in 1..$ArrayDataRows) {
        [PSCustomObject] @{
            Number = $i
            Place = Get-Random -InputObject $PlaceList
            Color = Get-Random -InputObject $ColorList
            Zone = -join (Get-Random -InputObject $UC_LetterList -Count 10)
            Group = Get-Random -InputObject $GroupList
            }

        }
    }).TotalMilliseconds
# total ms = 24,390
讨论有关构建阵列(集合)的重要通用优化技术

难题的另一个重要部分是尽可能避免循环中的(多个)cmdlet调用

使用
[Random]
()替换
Get Random
调用可提供最大的加速比(PSv5+语法):

在我的机器上,上面的命令大约需要12秒,而您最初的命令运行了大约35分钟(!),这相当于大约175的加速系数


基准

以下是对比您的原始方法、Lee的优化版本和上面基于
[random]
的解决方案的示例计时;绝对数并不重要,但相对性能是重要的,如
Factor
列所示:

使用
1000
数组元素:

Factor Secs (10-run avg.) Command
------ ------------------ -------
1.00   0.100              # with [random]…
12.78  1.273              # with Get-Random - optimized…
13.45  1.340              # with Get-Random - original approach…
Factor Secs (10-run avg.) Command
------ ------------------ -------
1.00   1.082              # with [random]…
12.29  13.296             # with Get-Random - optimized…
20.40  22.081             # with Get-Random - original approach…
请注意,在1000个元素时,阵列构建方法的优化提供了一些但不是很大的加速,但是元素越多,好处就越大

使用
10000
数组元素:

Factor Secs (10-run avg.) Command
------ ------------------ -------
1.00   0.100              # with [random]…
12.78  1.273              # with Get-Random - optimized…
13.45  1.340              # with Get-Random - original approach…
Factor Secs (10-run avg.) Command
------ ------------------ -------
1.00   1.082              # with [random]…
12.29  13.296             # with Get-Random - optimized…
20.40  22.081             # with Get-Random - original approach…
有了10000个元素,阵列构建的优化已经获得了丰厚的回报

我没有耐心运行
150000
元素,但是很容易适应以下代码,它使用:


IIRC,你的
@()
每次你
+=
都在制作一份新的副本。使用
[System.Collections.ArrayList]
.Add()
,我敢打赌您的性能会提高。此外,对于所有这些inputObject,在循环外创建它们一次并存储在变量中。考虑到较小的尺寸,可以忽略不计,但仍然是一种优化。将内容放入集合的最快方法是使用
$collection=foreach()
。。。这将收集RAM中的所有项,并最终将它们一次填充到
$Collection
中。它实际上比
ArrayList
&
Generic.List
集合类型的
.Add()
方法更快。[grin]另外,您并不是在制作哈希表数组。。。您正在创建PSCustomObjects数组。[咧嘴笑]