Pertimbangan performa pembuatan skrip PowerShell
Skrip PowerShell yang memanfaatkan .NET secara langsung dan menghindari alur cenderung lebih cepat daripada PowerShell idiomatik. Idiomatic PowerShell menggunakan cmdlet dan fungsi PowerShell, sering memanfaatkan alur, dan menggunakan ke .NET hanya jika perlu.
Nota
Banyak teknik yang dijelaskan di sini bukan PowerShell idiomatik dan dapat mengurangi keterbacaan skrip PowerShell. Penulis skrip disarankan untuk menggunakan PowerShell idiomatik kecuali performa menentukan sebaliknya.
Menekan output
Ada banyak cara untuk menghindari penulisan objek ke alur.
- Penugasan atau pengalihan file ke
$null
- Transmisi ke
[void]
- Pipa ke
Out-Null
Kecepatan penugasan ke $null
, transmisi ke [void]
, dan pengalihan file ke $null
hampir identik. Namun, memanggil Out-Null
dalam perulangan besar dapat secara signifikan lebih lambat, terutama di PowerShell 5.1.
$tests = @{
'Assign to $null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$null = $arraylist.Add($i)
}
}
'Cast to [void]' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
[void] $arraylist.Add($i)
}
}
'Redirect to $null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$arraylist.Add($i) > $null
}
}
'Pipe to Out-Null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$arraylist.Add($i) | Out-Null
}
}
}
10kb, 50kb, 100kb | ForEach-Object {
$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value $_ }).TotalMilliseconds
[pscustomobject]@{
Iterations = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}
Pengujian ini dijalankan pada komputer Windows 11 di PowerShell 7.3.4. Hasilnya ditunjukkan di bawah ini:
Iterations Test TotalMilliseconds RelativeSpeed
---------- ---- ----------------- -------------
10240 Assign to $null 36.74 1x
10240 Redirect to $null 55.84 1.52x
10240 Cast to [void] 62.96 1.71x
10240 Pipe to Out-Null 81.65 2.22x
51200 Assign to $null 193.92 1x
51200 Cast to [void] 200.77 1.04x
51200 Redirect to $null 219.69 1.13x
51200 Pipe to Out-Null 329.62 1.7x
102400 Redirect to $null 386.08 1x
102400 Assign to $null 392.13 1.02x
102400 Cast to [void] 405.24 1.05x
102400 Pipe to Out-Null 572.94 1.48x
Waktu dan kecepatan relatif dapat bervariasi tergantung pada perangkat keras, versi PowerShell, dan beban kerja saat ini pada sistem.
Penambahan array
Membuat daftar item sering dilakukan menggunakan array dengan operator penambahan:
$results = @()
$results += Get-Something
$results += Get-SomethingElse
$results
Penambahan array tidak efisien karena array memiliki ukuran tetap. Setiap tambahan ke array membuat array baru yang cukup besar untuk menahan semua elemen operand kiri dan kanan. Elemen kedua operand disalin ke dalam array baru. Untuk koleksi kecil, overhead ini mungkin tidak masalah. Performa dapat menderita untuk koleksi besar.
Ada beberapa alternatif. Jika Anda tidak benar-benar memerlukan array, pertimbangkan untuk menggunakan daftar generik yang ditik ([List<T>]
):
$results = [System.Collections.Generic.List[object]]::new()
$results.AddRange((Get-Something))
$results.AddRange((Get-SomethingElse))
$results
Dampak performa penggunaan penambahan array tumbuh secara eksponensial dengan ukuran koleksi dan penambahan angka. Kode ini membandingkan secara eksplisit menetapkan nilai ke array dengan menggunakan penambahan array dan menggunakan metode Add(T)
pada objek [List<T>]
. Ini mendefinisikan penetapan eksplisit sebagai garis besar untuk performa.
$tests = @{
'PowerShell Explicit Assignment' = {
param($count)
$result = foreach($i in 1..$count) {
$i
}
}
'.Add(T) to List<T>' = {
param($count)
$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result.Add($i)
}
}
'+= Operator to Array' = {
param($count)
$result = @()
foreach($i in 1..$count) {
$result += $i
}
}
}
5kb, 10kb, 100kb | ForEach-Object {
$groupResult = foreach($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value -Count $_ }).TotalMilliseconds
[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}
Pengujian ini dijalankan pada komputer Windows 11 di PowerShell 7.3.4.
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
5120 PowerShell Explicit Assignment 26.65 1x
5120 .Add(T) to List<T> 110.98 4.16x
5120 += Operator to Array 402.91 15.12x
10240 PowerShell Explicit Assignment 0.49 1x
10240 .Add(T) to List<T> 137.67 280.96x
10240 += Operator to Array 1678.13 3424.76x
102400 PowerShell Explicit Assignment 11.18 1x
102400 .Add(T) to List<T> 1384.03 123.8x
102400 += Operator to Array 201991.06 18067.18x
Saat Anda bekerja dengan koleksi besar, penambahan array secara dramatis lebih lambat daripada menambahkan ke List<T>
.
Saat menggunakan objek [List<T>]
, Anda perlu membuat daftar dengan jenis tertentu, seperti [String]
atau [Int]
. Saat Anda menambahkan objek dari jenis yang berbeda ke daftar, objek tersebut ditransmisikan ke jenis yang ditentukan. Jika mereka tidak dapat ditransmisikan ke jenis yang ditentukan, metode akan menimbulkan pengecualian.
$intList = [System.Collections.Generic.List[int]]::new()
$intList.Add(1)
$intList.Add('2')
$intList.Add(3.0)
$intList.Add('Four')
$intList
MethodException:
Line |
5 | $intList.Add('Four')
| ~~~~~~~~~~~~~~~~~~~~
| Cannot convert argument "item", with value: "Four", for "Add" to type
"System.Int32": "Cannot convert value "Four" to type "System.Int32".
Error: "The input string 'Four' was not in a correct format.""
1
2
3
Saat Anda memerlukan daftar untuk menjadi kumpulan berbagai jenis objek, buatlah dengan [Object]
sebagai jenis daftar. Anda dapat menghitung koleksi memeriksa jenis objek di dalamnya.
$objectList = [System.Collections.Generic.List[object]]::new()
$objectList.Add(1)
$objectList.Add('2')
$objectList.Add(3.0)
$objectList | ForEach-Object { "$_ is $($_.GetType())" }
1 is int
2 is string
3 is double
Jika Anda memerlukan array, Anda dapat memanggil metode ToArray()
dalam daftar atau Anda dapat membiarkan PowerShell membuat array untuk Anda:
$results = @(
Get-Something
Get-SomethingElse
)
Dalam contoh ini, PowerShell membuat [ArrayList]
untuk menahan hasil yang ditulis ke alur di dalam ekspresi array. Tepat sebelum menetapkan ke $results
, PowerShell mengonversi [ArrayList]
menjadi [Object[]]
.
Penambahan string
String tidak dapat diubah. Setiap penambahan pada string benar-benar membuat string baru yang cukup besar untuk menahan konten operand kiri dan kanan, lalu menyalin elemen kedua operand ke dalam string baru. Untuk string kecil, overhead ini mungkin tidak masalah. Untuk string besar, ini dapat memengaruhi performa dan konsumsi memori.
Setidaknya ada dua alternatif:
- Operator
-join
menggabungkan string - Kelas .NET
[StringBuilder]
menyediakan string yang dapat diubah
Contoh berikut membandingkan performa ketiga metode membangun string ini.
$tests = @{
'StringBuilder' = {
$sb = [System.Text.StringBuilder]::new()
foreach ($i in 0..$args[0]) {
$sb = $sb.AppendLine("Iteration $i")
}
$sb.ToString()
}
'Join operator' = {
$string = @(
foreach ($i in 0..$args[0]) {
"Iteration $i"
}
) -join "`n"
$string
}
'Addition Assignment +=' = {
$string = ''
foreach ($i in 0..$args[0]) {
$string += "Iteration $i`n"
}
$string
}
}
10kb, 50kb, 100kb | ForEach-Object {
$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value $_ }).TotalMilliseconds
[pscustomobject]@{
Iterations = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}
Pengujian ini dijalankan pada komputer Windows 11 di PowerShell 7.4.2. Output menunjukkan bahwa operator -join
adalah yang tercepat, diikuti oleh kelas [StringBuilder]
.
Iterations Test TotalMilliseconds RelativeSpeed
---------- ---- ----------------- -------------
10240 Join operator 14.75 1x
10240 StringBuilder 62.44 4.23x
10240 Addition Assignment += 619.64 42.01x
51200 Join operator 43.15 1x
51200 StringBuilder 304.32 7.05x
51200 Addition Assignment += 14225.13 329.67x
102400 Join operator 85.62 1x
102400 StringBuilder 499.12 5.83x
102400 Addition Assignment += 67640.79 790.01x
Waktu dan kecepatan relatif dapat bervariasi tergantung pada perangkat keras, versi PowerShell, dan beban kerja saat ini pada sistem.
Memproses file besar
Cara idiomatik untuk memproses file di PowerShell mungkin terlihat seperti:
Get-Content $path | Where-Object Length -GT 10
Ini bisa menjadi urutan besarnya lebih lambat daripada menggunakan API .NET secara langsung. Misalnya, Anda dapat menggunakan kelas .NET [StreamReader]
:
try {
$reader = [System.IO.StreamReader]::new($path)
while (-not $reader.EndOfStream) {
$line = $reader.ReadLine()
if ($line.Length -gt 10) {
$line
}
}
}
finally {
if ($reader) {
$reader.Dispose()
}
}
Anda juga dapat menggunakan metode ReadLines
[System.IO.File]
, yang membungkus StreamReader
, menyederhanakan proses membaca:
foreach ($line in [System.IO.File]::ReadLines($path)) {
if ($line.Length -gt 10) {
$line
}
}
Mencari entri menurut properti dalam koleksi besar
Biasanya perlu menggunakan properti bersama untuk mengidentifikasi rekaman yang sama dalam koleksi yang berbeda, seperti menggunakan nama untuk mengambil ID dari satu daftar dan email dari daftar lain. Iterasi di atas daftar pertama untuk menemukan rekaman yang cocok di koleksi kedua lambat. Secara khusus, pemfilteran berulang koleksi kedua memiliki overhead besar.
Diberikan dua koleksi, satu dengan ID
$Employees = 1..10000 | ForEach-Object {
[PSCustomObject]@{
Id = $_
Name = "Name$_"
}
}
$Accounts = 2500..7500 | ForEach-Object {
[PSCustomObject]@{
Name = "Name$_"
Email = "Name$_@fabrikam.com"
}
}
Cara biasa untuk mendamaikan koleksi ini untuk mengembalikan daftar objek dengan ID
$Results = $Employees | ForEach-Object -Process {
$Employee = $_
$Account = $Accounts | Where-Object -FilterScript {
$_.Name -eq $Employee.Name
}
[pscustomobject]@{
Id = $Employee.Id
Name = $Employee.Name
Email = $Account.Email
}
}
Namun, implementasi tersebut harus memfilter semua 5000 item dalam koleksi $Accounts
sekali untuk setiap item dalam koleksi $Employee
. Itu bisa memakan waktu beberapa menit, bahkan untuk pencarian nilai tunggal ini.
Sebagai gantinya, Anda dapat membuat Tabel Hash
$LookupHash = @{}
foreach ($Account in $Accounts) {
$LookupHash[$Account.Name] = $Account
}
Mencari kunci dalam tabel hash jauh lebih cepat daripada memfilter koleksi menurut nilai properti. Alih-alih memeriksa setiap item dalam koleksi, PowerShell dapat memeriksa apakah kunci ditentukan dan menggunakan nilainya.
$Results = $Employees | ForEach-Object -Process {
$Email = $LookupHash[$_.Name].Email
[pscustomobject]@{
Id = $_.Id
Name = $_.Name
Email = $Email
}
}
Ini jauh lebih cepat. Sementara filter perulangan membutuhkan waktu beberapa menit untuk diselesaikan, pencarian hash membutuhkan waktu kurang dari satu detik.
Gunakan Write-Host dengan hati-hati
Perintah
Write-Host
dapat berupa urutan besaran yang lebih lambat dari [Console]::WriteLine()
untuk host tertentu seperti pwsh.exe
, powershell.exe
, atau powershell_ise.exe
. Namun, [Console]::WriteLine()
tidak dijamin berfungsi di semua host. Selain itu, output yang ditulis menggunakan [Console]::WriteLine()
tidak ditulis ke transkrip yang dimulai oleh Start-Transcript
.
Kompilasi JIT
PowerShell mengkompilasi kode skrip ke bytecode yang ditafsirkan. Dimulai di PowerShell 3, untuk kode yang berulang kali dijalankan dalam perulangan, PowerShell dapat meningkatkan performa dengan Just-in-time (JIT) yang mengkompilasi kode ke dalam kode asli.
Perulangan yang memiliki kurang dari 300 instruksi memenuhi syarat untuk kompilasi JIT. Perulangan yang lebih besar dari itu terlalu mahal untuk dikompilasi. Ketika perulangan telah dijalankan 16 kali, skrip dikompilasi JIT di latar belakang. Ketika kompilasi JIT selesai, eksekusi ditransfer ke kode yang dikompilasi.
Hindari panggilan berulang ke fungsi
Memanggil fungsi bisa menjadi operasi yang mahal. Jika Anda memanggil fungsi dalam perulangan ketat yang berjalan lama, pertimbangkan untuk memindahkan perulangan di dalam fungsi.
Pertimbangkan contoh berikut:
$tests = @{
'Simple for-loop' = {
param([int] $RepeatCount, [random] $RanGen)
for ($i = 0; $i -lt $RepeatCount; $i++) {
$null = $RanGen.Next()
}
}
'Wrapped in a function' = {
param([int] $RepeatCount, [random] $RanGen)
function Get-RandomNumberCore {
param ($rng)
$rng.Next()
}
for ($i = 0; $i -lt $RepeatCount; $i++) {
$null = Get-RandomNumberCore -rng $RanGen
}
}
'for-loop in a function' = {
param([int] $RepeatCount, [random] $RanGen)
function Get-RandomNumberAll {
param ($rng, $count)
for ($i = 0; $i -lt $count; $i++) {
$null = $rng.Next()
}
}
Get-RandomNumberAll -rng $RanGen -count $RepeatCount
}
}
5kb, 10kb, 100kb | ForEach-Object {
$rng = [random]::new()
$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = Measure-Command { & $test.Value -RepeatCount $_ -RanGen $rng }
[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms.TotalMilliseconds,2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}
Contoh
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
5120 for-loop in a function 9.62 1x
5120 Simple for-loop 10.55 1.1x
5120 Wrapped in a function 62.39 6.49x
10240 Simple for-loop 17.79 1x
10240 for-loop in a function 18.48 1.04x
10240 Wrapped in a function 127.39 7.16x
102400 for-loop in a function 179.19 1x
102400 Simple for-loop 181.58 1.01x
102400 Wrapped in a function 1155.57 6.45x
Hindari membungkus alur cmdlet
Sebagian besar cmdlet diimplementasikan untuk alur, yang merupakan sintaks dan proses berurutan. Misalnya:
cmdlet1 | cmdlet2 | cmdlet3
Menginisialisasi alur baru bisa mahal, oleh karena itu Anda harus menghindari pembungkusan alur cmdlet ke dalam alur lain yang ada.
Pertimbangkan contoh berikut. File Input.csv
berisi 2100 baris. Perintah Export-Csv
dibungkus di dalam alur ForEach-Object
. Cmdlet Export-Csv
dipanggil untuk setiap iterasi perulangan ForEach-Object
.
$measure = Measure-Command -Expression {
Import-Csv .\Input.csv | ForEach-Object -Begin { $Id = 1 } -Process {
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
} | Export-Csv .\Output1.csv -Append
}
}
'Wrapped = {0:N2} ms' -f $measure.TotalMilliseconds
Wrapped = 15,968.78 ms
Untuk contoh berikutnya, perintah Export-Csv
dipindahkan ke luar alur ForEach-Object
.
Dalam hal ini, Export-Csv
hanya dipanggil sekali, tetapi masih memproses semua objek yang dilewatkan dari ForEach-Object
.
$measure = Measure-Command -Expression {
Import-Csv .\Input.csv | ForEach-Object -Begin { $Id = 2 } -Process {
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
}
} | Export-Csv .\Output2.csv
}
'Unwrapped = {0:N2} ms' -f $measure.TotalMilliseconds
Unwrapped = 42.92 ms
Contoh yang tidak dibungkus 372 kali lebih cepat. Perhatikan juga bahwa implementasi pertama memerlukan parameter Tambahkan, yang tidak diperlukan untuk implementasi nanti.
Pembuatan objek
Membuat objek menggunakan cmdlet New-Object
bisa lambat. Kode berikut membandingkan performa pembuatan objek menggunakan cmdlet New-Object
dengan akselerator jenis [pscustomobject]
.
Measure-Command {
$test = 'PSCustomObject'
for ($i = 0; $i -lt 100000; $i++) {
$resultObject = [PSCustomObject]@{
Name = 'Name'
Path = 'FullName'
}
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
Measure-Command {
$test = 'New-Object'
for ($i = 0; $i -lt 100000; $i++) {
$resultObject = New-Object -TypeName PSObject -Property @{
Name = 'Name'
Path = 'FullName'
}
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
Test TotalSeconds
---- ------------
PSCustomObject 0.48
New-Object 3.37
PowerShell 5.0 menambahkan metode statis new()
untuk semua jenis .NET. Kode berikut membandingkan performa pembuatan objek menggunakan cmdlet New-Object
dengan metode new()
.
Measure-Command {
$test = 'new() method'
for ($i = 0; $i -lt 100000; $i++) {
$sb = [System.Text.StringBuilder]::new(1000)
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
Measure-Command {
$test = 'New-Object'
for ($i = 0; $i -lt 100000; $i++) {
$sb = New-Object -TypeName System.Text.StringBuilder -ArgumentList 1000
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
Test TotalSeconds
---- ------------
new() method 0.59
New-Object 3.17
Menggunakan OrderedDictionary untuk membuat objek baru secara dinamis
Ada situasi di mana kita mungkin perlu membuat objek secara dinamis berdasarkan beberapa input, cara yang mungkin paling umum digunakan untuk membuat PSObject
Asumsikan Anda memiliki respons API berikut yang disimpan dalam variabel $json
.
{
"tables": [
{
"name": "PrimaryResult",
"columns": [
{ "name": "Type", "type": "string" },
{ "name": "TenantId", "type": "string" },
{ "name": "count_", "type": "long" }
],
"rows": [
[ "Usage", "63613592-b6f7-4c3d-a390-22ba13102111", "1" ],
[ "Usage", "d436f322-a9f4-4aad-9a7d-271fbf66001c", "1" ],
[ "BillingFact", "63613592-b6f7-4c3d-a390-22ba13102111", "1" ],
[ "BillingFact", "d436f322-a9f4-4aad-9a7d-271fbf66001c", "1" ],
[ "Operation", "63613592-b6f7-4c3d-a390-22ba13102111", "7" ],
[ "Operation", "d436f322-a9f4-4aad-9a7d-271fbf66001c", "5" ]
]
}
]
}
Sekarang, misalkan Anda ingin mengekspor data ini ke CSV. Pertama, Anda perlu membuat objek baru dan menambahkan properti dan nilai menggunakan cmdlet Add-Member
.
$data = $json | ConvertFrom-Json
$columns = $data.tables.columns
$result = foreach ($row in $data.tables.rows) {
$obj = [psobject]::new()
$index = 0
foreach ($column in $columns) {
$obj | Add-Member -MemberType NoteProperty -Name $column.name -Value $row[$index++]
}
$obj
}
Menggunakan OrderedDictionary
, kode dapat diterjemahkan ke:
$data = $json | ConvertFrom-Json
$columns = $data.tables.columns
$result = foreach ($row in $data.tables.rows) {
$obj = [ordered]@{}
$index = 0
foreach ($column in $columns) {
$obj[$column.name] = $row[$index++]
}
[pscustomobject] $obj
}
Dalam kedua kasus, output $result
akan sama:
Type TenantId count_
---- -------- ------
Usage 63613592-b6f7-4c3d-a390-22ba13102111 1
Usage d436f322-a9f4-4aad-9a7d-271fbf66001c 1
BillingFact 63613592-b6f7-4c3d-a390-22ba13102111 1
BillingFact d436f322-a9f4-4aad-9a7d-271fbf66001c 1
Operation 63613592-b6f7-4c3d-a390-22ba13102111 7
Operation d436f322-a9f4-4aad-9a7d-271fbf66001c 5
Pendekatan terakhir menjadi secara eksponensial lebih efisien saat jumlah objek dan properti anggota meningkat.
Berikut adalah perbandingan performa tiga teknik untuk membuat objek dengan 5 properti:
$tests = @{
'[ordered] into [pscustomobject] cast' = {
param([int] $iterations, [string[]] $props)
foreach ($i in 1..$iterations) {
$obj = [ordered]@{}
foreach ($prop in $props) {
$obj[$prop] = $i
}
[pscustomobject] $obj
}
}
'Add-Member' = {
param([int] $iterations, [string[]] $props)
foreach ($i in 1..$iterations) {
$obj = [psobject]::new()
foreach ($prop in $props) {
$obj | Add-Member -MemberType NoteProperty -Name $prop -Value $i
}
$obj
}
}
'PSObject.Properties.Add' = {
param([int] $iterations, [string[]] $props)
# this is how, behind the scenes, `Add-Member` attaches
# new properties to our PSObject.
# Worth having it here for performance comparison
foreach ($i in 1..$iterations) {
$obj = [psobject]::new()
foreach ($prop in $props) {
$obj.PSObject.Properties.Add(
[psnoteproperty]::new($prop, $i))
}
$obj
}
}
}
$properties = 'Prop1', 'Prop2', 'Prop3', 'Prop4', 'Prop5'
1kb, 10kb, 100kb | ForEach-Object {
$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = Measure-Command { & $test.Value -iterations $_ -props $properties }
[pscustomobject]@{
Iterations = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms.TotalMilliseconds, 2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}
Dan ini adalah hasilnya:
Iterations Test TotalMilliseconds RelativeSpeed
---------- ---- ----------------- -------------
1024 [ordered] into [pscustomobject] cast 22.00 1x
1024 PSObject.Properties.Add 153.17 6.96x
1024 Add-Member 261.96 11.91x
10240 [ordered] into [pscustomobject] cast 65.24 1x
10240 PSObject.Properties.Add 1293.07 19.82x
10240 Add-Member 2203.03 33.77x
102400 [ordered] into [pscustomobject] cast 639.83 1x
102400 PSObject.Properties.Add 13914.67 21.75x
102400 Add-Member 23496.08 36.72x
Tautan terkait
$null
[void]
-
Out-Null List<T>
- metode
[String]
[Int]
[Object]
- metode
[ArrayList]
[StringBuilder]
[StreamReader]
- metode
-
Write-Host - Add-Member