Untuk melengkapi jawaban yang sudah ada sebelumnya, jawaban yang bermanfaat dengan panduan kapan harus menggunakan pendekatan mana dan perbandingan kinerja .
Di luar pipa, gunakan (PSv3 +):
$ objek . Nama
seperti yang ditunjukkan dalam jawaban rageandqq , yang secara sintaksis lebih sederhana dan lebih cepat .
Dalam pipa yang hasilnya harus diproses lebih lanjut atau hasilnya tidak sesuai dengan memori secara keseluruhan, gunakan:
$ objek | Select-Object -ExpandProperty Name
- Kebutuhan untuk
-ExpandProperty
dijelaskan dalam jawaban Scott Saad .
- Anda mendapatkan manfaat pipa biasa dari pemrosesan satu-per-satu, yang biasanya menghasilkan output segera dan menjaga penggunaan memori konstan (kecuali jika Anda akhirnya mengumpulkan hasilnya dalam memori pula).
- Pengorbanan :
- Penggunaan pipa relatif lambat .
Untuk koleksi input kecil (array), Anda mungkin tidak akan melihat perbedaannya , dan, terutama pada baris perintah, kadang-kadang bisa mengetik perintah dengan mudah lebih penting.
Berikut ini adalah alternatif yang mudah diketik , yang, bagaimanapun, merupakan pendekatan paling lambat ; menggunakan sintaks yang disederhanakan yang ForEach-Object
disebut pernyataan operasi (sekali lagi, PSv3 +):; mis., solusi PSv3 + berikut ini mudah ditambahkan ke perintah yang ada:
$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }
Demi kelengkapan: Metode array PSv4 + yang kurang.ForEach()
dikenal , lebih lengkap dibahas dalam artikel ini , adalah alternatif lain :
# By property name (string):
$objects.ForEach('Name')
# By script block (more flexibility; like ForEach-Object)
$objects.ForEach({ $_.Name })
Pendekatan ini mirip dengan penghitungan anggota , dengan pengorbanan yang sama, kecuali bahwa logika pipa tidak diterapkan; ini sedikit lebih lambat , meskipun masih terasa lebih cepat daripada pipa.
Untuk mengekstraksi nilai properti tunggal dengan nama ( argumen string ), solusi ini setara dengan enumerasi anggota (meskipun yang terakhir secara sintaksis lebih sederhana).
The Script-blok varian , memungkinkan sewenang-wenang transformasi ; ini adalah alternatif yang lebih cepat - all-in-memory-at-sekaligus - ke ForEach-Object
cmdlet berbasis-pipa ( %
) .
Membandingkan kinerja berbagai pendekatan
Berikut adalah contoh waktu untuk berbagai pendekatan, berdasarkan pada kumpulan input 10,000
objek , rata-rata di 10 run; angka absolut tidak penting dan bervariasi berdasarkan banyak faktor, tetapi seharusnya memberi Anda rasa kinerja relatif (timing berasal dari satu-core Windows 10 VM:
Penting
Kinerja relatif bervariasi berdasarkan pada apakah objek input adalah instance dari .NET Type (misalnya, sebagai output oleh Get-ChildItem
) atau [pscustomobject]
instance (misalnya, sebagai output oleh Convert-FromCsv
).
Alasannya adalah bahwa [pscustomobject]
properti dikelola secara dinamis oleh PowerShell, dan itu dapat mengaksesnya lebih cepat daripada properti biasa dari tipe .NET biasa (yang ditentukan secara statis). Kedua skenario dibahas di bawah ini.
Pengujian menggunakan koleksi yang sudah ada dalam memori-dalam-penuh sebagai input, sehingga dapat fokus pada kinerja ekstraksi properti murni. Dengan cmdlet streaming / panggilan fungsi sebagai input, perbedaan kinerja umumnya akan jauh lebih sedikit, karena waktu yang dihabiskan di dalam panggilan itu mungkin merupakan bagian dari sebagian besar waktu yang dihabiskan.
Untuk singkatnya, alias %
digunakan untuk ForEach-Object
cmdlet.
Kesimpulan umum , berlaku untuk tipe dan [pscustomobject]
input .NET reguler :
Penghitungan anggota ( $collection.Name
) dan foreach ($obj in $collection)
solusi sejauh ini tercepat , dengan faktor 10 atau lebih cepat daripada solusi berbasis pipa tercepat.
Anehnya, % Name
performanya jauh lebih buruk daripada % { $_.Name }
- lihat masalah GitHub ini .
PowerShell Core secara konsisten mengungguli Windows Powershell di sini.
Pengaturan waktu dengan tipe .NET biasa :
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.005
1.06 foreach($o in $objects) { $o.Name } 0.005
6.25 $objects.ForEach('Name') 0.028
10.22 $objects.ForEach({ $_.Name }) 0.046
17.52 $objects | % { $_.Name } 0.079
30.97 $objects | Select-Object -ExpandProperty Name 0.140
32.76 $objects | % Name 0.148
- Windows PowerShell v5.1.18362.145
Comparing property-value extraction methods with 10000 input objects, averaged over 10 runs...
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.012
1.32 foreach($o in $objects) { $o.Name } 0.015
9.07 $objects.ForEach({ $_.Name }) 0.105
10.30 $objects.ForEach('Name') 0.119
12.70 $objects | % { $_.Name } 0.147
27.04 $objects | % Name 0.312
29.70 $objects | Select-Object -ExpandProperty Name 0.343
Kesimpulan:
- Di PowerShell Core ,
.ForEach('Name')
jelas mengungguli .ForEach({ $_.Name })
. Di Windows PowerShell, anehnya, yang terakhir lebih cepat, meskipun hanya sedikit.
Pengaturan waktu dengan [pscustomobject]
instance :
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.006
1.11 foreach($o in $objects) { $o.Name } 0.007
1.52 $objects.ForEach('Name') 0.009
6.11 $objects.ForEach({ $_.Name }) 0.038
9.47 $objects | Select-Object -ExpandProperty Name 0.058
10.29 $objects | % { $_.Name } 0.063
29.77 $objects | % Name 0.184
- Windows PowerShell v5.1.18362.145
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.008
1.14 foreach($o in $objects) { $o.Name } 0.009
1.76 $objects.ForEach('Name') 0.015
10.36 $objects | Select-Object -ExpandProperty Name 0.085
11.18 $objects.ForEach({ $_.Name }) 0.092
16.79 $objects | % { $_.Name } 0.138
61.14 $objects | % Name 0.503
Kesimpulan:
Perhatikan bagaimana dengan [pscustomobject]
input yang .ForEach('Name')
jauh melebihi varian berbasis blok script .ForEach({ $_.Name })
,.
Demikian pula, [pscustomobject]
input membuat berbasis pipa Select-Object -ExpandProperty Name
lebih cepat, di Windows PowerShell hampir setara .ForEach({ $_.Name })
, tetapi di PowerShell Core masih sekitar 50% lebih lambat.
Singkatnya: Dengan pengecualian aneh % Name
, dengan [pscustomobject]
metode berbasis string untuk mereferensikan properti mengungguli yang berbasis scriptblock.
Kode sumber untuk tes :
catatan:
$count = 1e4 # max. input object count == 10,000
$runs = 10 # number of runs to average
# Note: Using [pscustomobject] instances rather than instances of
# regular .NET types changes the performance characteristics.
# Set this to $true to test with [pscustomobject] instances below.
$useCustomObjectInput = $false
# Create sample input objects.
if ($useCustomObjectInput) {
# Use [pscustomobject] instances.
$objects = 1..$count | % { [pscustomobject] @{ Name = "$foobar_$_"; Other1 = 1; Other2 = 2; Other3 = 3; Other4 = 4 } }
} else {
# Use instances of a regular .NET type.
# Note: The actual count of files and folders in your home dir. tree
# may be less than $count
$objects = Get-ChildItem -Recurse $HOME | Select-Object -First $count
}
Write-Host "Comparing property-value extraction methods with $($objects.Count) input objects, averaged over $runs runs..."
# An array of script blocks with the various approaches.
$approaches = { $objects | Select-Object -ExpandProperty Name },
{ $objects | % Name },
{ $objects | % { $_.Name } },
{ $objects.ForEach('Name') },
{ $objects.ForEach({ $_.Name }) },
{ $objects.Name },
{ foreach($o in $objects) { $o.Name } }
# Time the approaches and sort them by execution time (fastest first):
Time-Command $approaches -Count $runs | Select Factor, Command, Secs*
$results = @($objects | %{ $_.Name })
. Ini bisa lebih mudah untuk mengetik di baris perintah di kali, meskipun saya pikir jawaban Scott umumnya lebih baik.