以下の内容はhttps://tech.guitarrapc.com/entry/2013/03/09/190318より取得しました。


PowerShell For / Foreach / Foreach-Object / ScriptBlock / Filter - Benchmark

There is C# benchmark for For VS Foreach. It was very interesting to use in code.

C# - For Vs Foreach - Benchmark 2013

Introduction

I could not found greate article for "Which is better practive among "For" VS "Foreach" in PowerShell". I believe there should be some point of view about it, but let's try benchmark int with way how original C# site doing. What about PowerShelll 1.0 and 2.0? Sorry but please forgive me only about PowerShell 3.0.

Target

Like other program languages like PowerShell also have several Loop and I have decided to benchmark for for, foreach, Foreach-Object, ScriptBlock and filter.

for
foreach
Foreach-Object
ScriptBlock
Filter

As you know, they wrote like this in PowerShell.

for (<Initialization Pipeline>; <Evaluate Pipeline>;<increment Pipeline>){< Sentence >}
foreach (<Variable> in <Loop Pipeline>){< Sentence>}
<Parameter> | Foreach-Object {begin}{process}{end}
&{Sentence}
filter <Name>{param(<List of Parameter>) <Sentence>}

The Benchmark Result

Followed Original site.

  • Measured: miliseconds
  • Collection length: 30000000
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 275899.00 265212.00 283013.40 274708.13
int int Foreach 186429.45 176947.98 198700.93 187359.46
int int Foreach-Object 1050280.06 1055265.18 1035663.52 1047069.58
int int ScriptBlock 227393.92 240253.13 224370.40 230672.48
int int Filter 237666.43 233423.09 233057.27 234715.60
int List For 340137.03 355315.28 335932.48 343794.93
int List Foreach 241257.27 260461.74 240227.87 247315.63
int List Foreach-Object 1160124.71 1290480.25 1156974.90 1202526.62
int List ScriptBlock 300991.85 322849.46 295052.61 306297.97
int List Filter 342645.71 308032.91 348444.29 347944.69
int ArrayList For 258247.16 280059.96 272251.21 270186.11
int ArrayList Foreach 162259.60 174109.73 172552.03 169640.45
int ArrayList Foreach-Object 997676.13 1079849.90 1057534.18 1045020.07
int ArrayList ScriptBlock 209276.20 232152.56 214621.41 218683.39
int ArrayList Filter 229675.65 230850.35 231555.98 231299.99

Conclusion

Speed of Collections

  • ArrayList (Fastest)
  • int
  • List (Slowest)

Data Type - Operation

All Datatype shows same disposition.

  • int[]
  • List
  • ArrayList

Foreach is the fastest, almost no difference between ScriptBlock and Filter. Foreach-Object seeems obviously slow.

  • Foreach (Fastest)
  • ScriptBlock
  • Filter
  • Foreach-Object (Slowest)

Which Loop type to be use

I should note such a cost for Foreach-Object Cmdlet.

Data Type Collection Type Loop Type Average v.s. int For v.s. int
int int For 274708.13 - -
int int Foreach 187359.46 68.20% -
int int Foreach-Object 1047069.58 381.16% -
int int ScriptBlock 230672.48 83.97% -
int int[] Filter 234715.60 85.44% -
int List For 343794.93 125.15% 125.15%
int List Foreach 247315.63 90.03% 132.00%
int List Foreach-Object 1202526.62 437.75% 114.85%
int List ScriptBlock 306297.97 111.50% 132.78%
int List Filter 347944.69 126.66% 148.24%
int ArrayList For 270186.11 98.35% 98.35%
int ArrayList Foreach 169640.45 61.75% 90.54%
int ArrayList Foreach-Object 1045020.07 380.41% 99.80%
int ArrayList ScriptBlock 218683.39 79.61% 94.80%
int ArrayList Filter 231299.99 84.20% 98.54%

It takes time V.S. "4 times of for", "5-6 time of foeach" and "4-4.5 time of ScriptBlock/Filter". Also ScriptBlock was next position of foreach and Filter shows almost same speed. I thought In-Action said Foreach-Object was just a one type of Filter, but benchmark result in it isn't. Filter should be takes cost for ScriptBlock {process{}} + set into PSObject:Function and was called. I don't to write foreach that foreach couldn't use in Pipeline, but now we can put Filter in alter choice. So I recomend as ...

  • foreach : for huge data like Log file and when it doesn't need to use the Pipeline
  • Filter : It data was quite big but requried to use the Pipeline
  • ScriptBlock : When using standalone, I mean not for the Pipeline or foreach statesment
  • Foreach-Object : When required to pass Object through the Pipeline, also data was small and speed should be not considerble

How about Collection size to take cost take exponential

There is no exponential trend but only propotion to Collection size. You can estimate time spend.

  • Foreach (Fastest)
  • ScriptBlock
  • Filter
  • Foreach-Object (Slowest)

Here's result with Collection size for 10,100,1000,10000,100000,1000000.

Measured in miliseconds Collection length: 10

Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 0.15 0.22 0.21 0.19
int int Foreach 0.24 0.15 0.11 0.17
int int Foreach-Object 0.57 0.62 0.67 0.62
int int ScriptBlock 0.19 0.26 0.22 0.22
int int Filter 0.21 0.20 0.19 0.20
int List For 0.19 0.24 0.16 0.20
int List Foreach 0.13 0.33 0.13 0.19
int List Foreach-Object 0.48 0.66 0.64 0.59
int List ScriptBlock 0.30 0.28 0.24 0.27
int List Filter 0.34 0.18 0.19 0.24
int ArrayList For 0.12 0.23 0.13 0.16
int ArrayList Foreach 0.09 0.19 0.10 0.13
int ArrayList Foreach-Object 0.42 0.77 0.50 0.56
int ArrayList ScriptBlock 0.15 0.25 0.20 0.20
int ArrayList Filter 0.16 0.19 0.15 0.17
  • Measured in miliseconds
  • Collection length: 100
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 1.08 0.90 1.08 1.02
int int Foreach 0.66 0.67 0.69 0.67
int int Foreach-Object 3.64 3.49 3.59 3.57
int int ScriptBlock 0.94 0.85 0.96 0.91
int int Filter 1.02 1.07 1.05 1.05
int List For 1.24 1.15 1.17 1.19
int List Foreach 0.92 2.91 0.97 1.60
int List Foreach-Object 7.69 4.48 4.21 5.46
int List ScriptBlock 1.16 1.20 1.07 1.14
int List Filter 1.26 1.25 1.05 1.19
int ArrayList For 1.01 0.99 1.13 1.04
int ArrayList Foreach 0.67 0.77 0.57 0.67
int ArrayList Foreach-Object 8.37 3.50 3.52 5.13
int ArrayList ScriptBlock 0.76 0.79 0.75 0.77
int ArrayList Filter 0.75 0.97 0.78 0.84
  • Measured in miliseconds
  • Collection length: 1000
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 13.13 12.11 10.33 11.86
int int Foreach 7.38 6.54 6.70 6.88
int int Foreach-Object 41.38 39.61 37.85 39.61
int int ScriptBlock 10.03 8.14 10.27 9.48
int int Filter 8.97 9.04 7.33 8.45
int List For 15.10 12.45 13.04 13.53
int List Foreach 9.94 9.86 8.30 9.37
int List Foreach-Object 45.20 41.35 44.35 43.63
int List ScriptBlock 12.36 10.13 10.42 10.97
int List Filter 12.11 10.80 9.74 10.88
int ArrayList For 9.13 9.46 11.98 10.19
int ArrayList Foreach 6.23 6.95 6.35 6.51
int ArrayList Foreach-Object 39.64 40.04 37.64 39.11
int ArrayList ScriptBlock 7.65 7.15 7.17 7.32
int ArrayList Filter 6.92 7.19 9.17 7.76
  • Measured in miliseconds
  • Collection length: 10000
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 105.29 100.37 97.21 100.95
int int Foreach 68.30 66.19 65.25 66.58
int int Foreach-Object 386.23 367.49 377.58 377.10
int int ScriptBlock 87.87 80.90 83.52 84.10
int int Filter 84.34 82.42 80.99 82.58
int List For 132.17 125.16 121.24 126.19
int List Foreach 90.14 88.64 87.66 88.81
int List Foreach-Object 425.56 427.77 417.71 423.68
int List ScriptBlock 112.23 107.41 108.86 109.50
int List Filter 102.32 143.87 104.03 116.74
int ArrayList For 102.66 94.42 97.98 98.35
int ArrayList Foreach 63.03 62.88 63.24 63.05
int ArrayList Foreach-Object 374.20 369.76 376.02 373.33
int ArrayList ScriptBlock 86.63 80.63 80.79 82.68
int ArrayList Filter 75.81 76.07 76.78 76.22
  • Measured in miliseconds
  • Collection length: 100000
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 928.67 989.31 934.40 950.79
int int Foreach 639.67 655.97 648.20 647.95
int int Foreach-Object 3739.28 3814.27 3730.59 3761.38
int int ScriptBlock 817.40 820.79 808.26 815.49
int int Filter 84.34 82.42 80.99 82.58
int List For 132.17 125.16 121.24 126.19
int List Foreach 90.14 88.64 87.66 88.81
int List Foreach-Object 425.56 427.77 417.71 423.68
int List ScriptBlock 112.23 107.41 108.86 109.50
int List Filter 102.32 143.87 104.03 116.74
int ArrayList For 941.65 937.21 946.71 941.86
int ArrayList Foreach 622.43 593.67 589.76 601.95
int ArrayList Foreach-Object 3574.23 3654.80 3646.56 3625.19
int ArrayList ScriptBlock 765.73 818.17 776.87 786.92
int ArrayList Filter 759.23 747.40 743.89 750.17
  • Measured in miliseconds
  • Collection length: 1000000
Data Type Collection Type Loop Type Test 1 Test 2 Test 3 Average
int int For 9744.00 9438.96 9758.17 9647.04
int int Foreach 6766.58 6401.43 6640.43 6602.81
int int Foreach-Object 38629.84 37763.99 38132.47 38175.43
int int ScriptBlock 8480.02 8277.16 8329.73 8362.30
int int Filter 8326.80 8178.34 8076.98 8194.04
int List For 12840.89 12497.00 12669.28 12669.06
int List Foreach 8913.08 8733.64 8840.35 8829.02
int List Foreach-Object 43677.32 42700.12 43606.07 43327.84
int List ScriptBlock 11180.41 10921.40 11042.95 11048.25
int List Filter 10552.67 10176.99 10198.66 10309.44
int ArrayList For 9361.94 9696.00 9582.81 9546.92
int ArrayList Foreach 6066.82 6069.82 6185.74 6107.46
int ArrayList Foreach-Object 36339.03 36905.48 37547.94 36930.82
int ArrayList ScriptBlock 7704.85 7682.98 7671.94 7686.59
int ArrayList Filter 7319.12 7521.99 7445.32 7428.81

Codes Used to Run the Test

Mesure-Object was sat in each function to measure time. I know It should take out of function if you want to measure CAST cost. Declare Filter:

filter Get-FilterTest{
 [decimal]$total += $_
}

Sample of For Loop Test.

function Get-intForTest{
  param($int)
  Measure-Command{
    for ($i = 0; $i -lt $int.length; $i++)
    {
      [decimal]$total += $int[$i]
    }
  }
}

Sample of Foreach Loop Test:

function Get-intForeachTest{
  param($int)
  Measure-Command{
    foreach ($i in $int)
    {
      [decimal]$total += $i
    }
  }
}

Sample of Foreach-Object Loop Test:

function Get-intForeachObjectTest{
  param($int)
  Measure-Command{
    $int | ForEach-Object {
      [decimal]$total += $_
    }
  }
}

Sample of ScriptBlock Loop Test:

function Get-intScriptBlockTest{
  param($int)
  Measure-Command{
    $int | &{process{[decimal]$total += $_}}
  }
}

Sample of Filter Loop Test:

function Get-intFilterTest{
  param($int)
  Measure-Command{
    $int | Get-FilterTest
  }
}

Declare Collection.

[int[]]$array=@()
$array += 1..30000000

Run code.

(Get-intForTest -int $array).TotalMilliseconds
(Get-intForeachTest -int $array).TotalMilliseconds
(Get-intForeachObjectTest -int $array).TotalMilliseconds
(Get-intScriptBlockTest -int $array).TotalMilliseconds
(Get-intFilterTest -int $array).TotalMilliseconds
(Get-intFilterTest -int $array).TotalMilliseconds

Here's whole code, it run 4 time to measure.

filter Get-FilterTest{
 [decimal]$total += $_
}

function Get-intForTest{
  param($int)
  Measure-Command{
    for ($i = 0; $i -lt $int.length; $i++)
    {
      [decimal]$total += $int[$i]
    }
  }
}

function Get-intForeachTest{
  param($int)
  Measure-Command{
    foreach ($i in $int)
    {
      [decimal]$total += $i
    }
  }

}

function Get-intForeachObjectTest{
  param($int)
  Measure-Command{
    $int | ForEach-Object{
      [decimal]$total += $_
    }
  }
}

function Get-intScriptBlockTest{
  param($int)
  Measure-Command{
    $int | &{process{[decimal]$total += $_}}
  }
}

function Get-intFilterTest{
  param($int)
  Measure-Command{
    $int | Get-FilterTest
  }
}

function Get-ListForTest{
  param($int)
  $list = New-Object 'System.Collections.Generic.List`1[System.String]'
  $int | foreach-Object { $list.Add($_)}

  #,$list

  Measure-Command{
    for ($i = 0; $i -lt $int.length; $i++)
    {
      [decimal]$total += $list[$i]
    }
  }
}

function Get-ListForeachTest{
  param($int)
  $list = New-Object 'System.Collections.Generic.List`1[System.String]'
  $int | foreach-Object { $list.Add($_)}

  #,$list

  Measure-Command{
    foreach ($l in $list)
    {
      [decimal]$total += $l
    }
  }
}

function Get-ListForeachObjectTest{
  param($int)
  $list = New-Object 'System.Collections.Generic.List`1[System.String]'
  $int | foreach-Object { $list.Add($_)}

  #,$list

  Measure-Command{
    $list | foreach-Object{
      [decimal]$total += $_
    }
  }
}

function Get-ListScriptBlockTest{
  param($int)
  $list = New-Object 'System.Collections.Generic.List`1[System.String]'
  $int | foreach-Object { $list.Add($_)}

  #,$list

  Measure-Command{
    $list | &{process{[decimal]$total += $_}}
  }
}

function Get-ListFilterTest{
  param($int)
  $list = New-Object 'System.Collections.Generic.List`1[System.String]'
  $int | foreach-Object { $list.Add($_)}

  #,$list

  Measure-Command{
    $list | Get-FilterTest
  }
}

function Get-ArrayListForTest{
  param($int)
  $arrayList = New-Object System.Collections.ArrayList
  [Void]($int | foreach-Object { $arrayList.Add($_) })

  #,$Arraylist

  Measure-Command{
    for ($i = 0; $i -lt $int.length; $i++)
    {
      [decimal]$total += $arrayList[$i]
    }
  }
}

function Get-ArrayListForeachTest{
  param($int)
  $arrayList = New-Object System.Collections.ArrayList
  [Void]($int | foreach-Object { $arrayList.Add($_) })

  #,$Arraylist

  Measure-Command{
    foreach ($al in $arrayList)
    {
      [decimal]$total += $al
    }
  }
}

function Get-ArrayListForeachObjectTest{
  param($int)
  $arrayList = New-Object System.Collections.ArrayList
  [Void]($int | foreach-Object { $arrayList.Add($_) })

  #,$Arraylist

  Measure-Command{
    $arrayList | Foreach-Object{
      [decimal]$total += $_
    }
  }
}

function Get-ArrayListScriptBlockTest{
  param($int)
  $arrayList = New-Object System.Collections.ArrayList
  [Void]($int | foreach-Object { $arrayList.Add($_) })

  #,$Arraylist

  Measure-Command{
    $arrayList | &{process{[decimal]$total += $_}}
  }
}

filter Get-ArrayListFilterTest{
  param($int)
  $arrayList = New-Object System.Collections.ArrayList
  [Void]($int | foreach-Object { $arrayList.Add($_) })

  #,$Arraylist
  Measure-Command {
    $arrayList | Get-FilterTest
  }
}

[int[]]$array=@()
$array += 1..30000000

foreach ($item in 1..4) {
  (Get-intForTest -int $array).TotalMilliseconds
  (Get-intForeachTest -int $array).TotalMilliseconds
  (Get-intForeachObjectTest -int $array).TotalMilliseconds
  (Get-intScriptBlockTest -int $array).TotalMilliseconds
  (Get-intFilterTest -int $array).TotalMilliseconds

  (Get-ListForTest -int $array).TotalMilliseconds
  (Get-ListForeachTest -int $array).TotalMilliseconds
  (Get-ListForeachObjectTest -int $array).TotalMilliseconds
  (Get-ListScriptBlockTest -int $array).TotalMilliseconds
  (Get-ListFilterTest -int $array).TotalMilliseconds

  (Get-ArrayListForTest -int $array).TotalMilliseconds
  (Get-ArrayListForeachTest -int $array).TotalMilliseconds
  (Get-ArrayListForeachObjectTest -int $array).TotalMilliseconds
  (Get-ArrayListScriptBlockTest -int $array).TotalMilliseconds
  (Get-ArrayListFilterTest -int $array).TotalMilliseconds
  ""
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL).




以上の内容はhttps://tech.guitarrapc.com/entry/2013/03/09/190318より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14