2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShell 配列への追加・要素変更のスピード比較 Collections・固定配列

Last updated at Posted at 2022-07-23

概要

PowerShellでサーバのDBからとってきた大量データを加工してCSV出力するときに、配列にデータ追加や要素変更をする必要があったので、PowerShellで使える配列のスピードを比較検証してみました。文字列で検証します。

やること
# 追加(System.Collections.ArrayList、System.Collections.Generic.List)
$array = New-Object System.Collections.ArrayList
$array = New-Object System.Collections.Generic.List
$array.Add("test1")

# 追加(固定配列)
$array = @()
$array += "test1"

# 変更(共通)
$array[$i] += ",test2,test3"

結果

追加 ArrayList Generic.List 固定配列
5,000回 0.001秒 0.001秒 0.55秒
10,000回 0.001秒 0.001秒 2.37秒
30,000回 0.007秒 0.003秒 27.75秒
500,000回 0.16秒 0.11秒 ---
2,000,000回 3.59秒 3.74秒 ---
変更 ArrayList Generic.List 固定配列
5,000回 0.003秒 0.0016秒 0.0016秒
10,000回 0.0016秒 0.0104秒 0.0014秒
30,000回 0.0072秒 0.011秒 0.0108秒
500,000回 0.14秒 0.23秒 ---
2,000,000回 4.95秒 5.22秒 ---

追加に関しては、固定配列は回数が増えると指数関数的に所要時間が増えていきました。500,000回以降は固定配列の所要時間を検証していません。それに対してCollectionsのArrayList、Generic.Listは追加する回数が増えても、指数関数的にはならず、かなり早いと思いました。

変更に関しては、すべての配列に大差なさそうです。

検証内容

  • 対象の配列(3種類)
    固定配列、System.Collections.ArrayList、System.Collections.Generic.List

  • 追加・要素変更回数(5種類)
    5,000回、10,000回、30,000回、500,000回、2,000,000回

  • 平均をとるために繰り返す回数
    5回

環境

Windows 10 21H2
CPU Corei7-3770S Memory 16GB

コード

test.ps1
# ArrayList(addで追加)
function ArrayListFunc([int]$count, [ref][long]$addTime, [ref][long]$changeTime) {
    $array = New-Object System.Collections.ArrayList
    $p1 = Get-Date
    # 追加
    for ($i=0; $i -lt $count; $i++){
        # $null = $array.Add("test1")
        $array.Add("test1")
    }
    $p2 = Get-Date
    # 変更
    for ($i=0; $i -lt $count; $i++){
        # $null = $array[$i] += ",test2,test3"
        $array[$i] += ",test2,test3"
    }
    $p3 = Get-Date
    # 計算
    $temp = $p2 - $p1
    $addTime.Value = [math]::Floor($temp.TotalMilliseconds)
    $temp = $p3 - $p2
    $changeTime.Value = [math]::Floor($temp.TotalMilliseconds)
}

# Generic.List(addで追加)
function GenericListFunc([int]$count, [ref][long]$addTime, [ref][long]$changeTime) {
    $array = New-Object System.Collections.Generic.List[string]
    $p1 = Get-Date
    # 追加
    for ($i=0; $i -lt $count; $i++){
        # $null = $array.Add("test1")
        $array.Add("test1")
    }
    $p2 = Get-Date
    # 変更
    for ($i=0; $i -lt $count; $i++){
        # $null = $array[$i] += ",test2,test3"
        $array[$i] += ",test2,test3"
    }
    $p3 = Get-Date
    # 計算
    $temp = $p2 - $p1
    $addTime.Value = [math]::Floor($temp.TotalMilliseconds)
    $temp = $p3 - $p2
    $changeTime.Value = [math]::Floor($temp.TotalMilliseconds)
}

# 固定配列(+=で追加)
function ArrayFunc([int]$count, [ref][long]$addTime, [ref][long]$changeTime) {
    $array = @()
    $p1 = Get-Date
    # 追加
    for ($i=0; $i -lt $count; $i++){
        # $null = $array += "test1"
        $array += "test1"
    }
    $p2 = Get-Date
    # 変更
    for ($i=0; $i -lt $count; $i++){
        # $null = $array[$i] += ",test2,test3"
        $array[$i] += ",test2,test3"
    }
    $p3 = Get-Date
    # 計算
    $temp = $p2 - $p1
    $addTime.Value = [math]::Floor($temp.TotalMilliseconds)
    $temp = $p3 - $p2
    $changeTime.Value = [math]::Floor($temp.TotalMilliseconds)
}

# 検証用関数
function TestFunc([int]$count, [int]$repeat, [ref]$addTimeArray, [ref]$changeTimeArray, `
                $isTestArrayList, $isTestGenericList, $isTestArray) {

    $addTime = 0
    $addTimeTotal_ArrayList = 0
    $addTimeTotal_GenericList = 0
    $addTimeTotal_Array = 0
    $changeTiem = 0
    $changeTimeTotal_ArrayList = 0
    $changeTimeTotal_GenericList = 0
    $changeTimeTotal_Array = 0

    for ($i=0; $i -lt $repeat; $i++) {
        if ($isTestArrayList) {
            ArrayListFunc $count ([ref]$addTime) ([ref]$changeTiem)
            $addTimeTotal_ArrayList += $addTime
            $changeTimeTotal_ArrayList += $changeTiem
        }
        
        if ($isTestGenericList) {
            GenericListFunc $count ([ref]$addTime) ([ref]$changeTiem)
            $addTimeTotal_GenericList += $addTime
            $changeTimeTotal_GenericList += $changeTiem
        }
       
        if ($isTestArray) {
            ArrayFunc $count ([ref]$addTime) ([ref]$changeTiem)
            $addTimeTotal_Array += $addTime
            $changeTimeTotal_Array += $changeTiem
        }
    }

    $addTimeArray.Value += 
    [String]($addTimeTotal_ArrayList / 1000 / $repeat) + "`t" `
    + [String]($addTimeTotal_GenericList / 1000 / $repeat) + "`t" `
    + [String]($addTimeTotal_Array / 1000 / $repeat)

    $changeTimeArray.Value += 
    [String]($changeTimeTotal_ArrayList / 1000 / $repeat) + "`t" `
    + [String]($changeTimeTotal_GenericList / 1000 / $repeat) + "`t" `
    + [String]($changeTimeTotal_Array / 1000 / $repeat)
}

# ここから検証
$addTimeArray = @()
$changeTimeArray = @()
$repeat = 5

# 5,000回
TestFunc 5000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $true

# 10,000回
TestFunc 10000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $true

# 30,000回
TestFunc 30000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $true

# 50,0000回
TestFunc 500000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $false

# 500,000回
TestFunc 500000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $false

# 2,000,000回
TestFunc 2000000 $repeat ([ref]$addTimeArray) ([ref]$changeTimeArray) $true $true $false

# 結果
Write-Host "追加"
foreach($output in $addTimeArray) {
    Write-Host $output
}
Write-Host "変更"
foreach($output in $changeTimeArray) {
    Write-Host $output
}
2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?