about_Thread_Jobs
Deskripsi singkat
Menyediakan informasi tentang pekerjaan berbasis utas PowerShell. Pekerjaan utas adalah jenis pekerjaan latar belakang yang menjalankan perintah atau ekspresi dalam utas terpisah dalam proses sesi saat ini.
Deskripsi panjang
PowerShell secara bersamaan menjalankan perintah dan skrip melalui pekerjaan. Ada tiga jenis pekerjaan yang disediakan oleh PowerShell untuk mendukung konkurensi.
RemoteJob
- Perintah dan skrip berjalan dalam sesi jarak jauh. Untuk informasi selengkapnya, lihat about_Remote_Jobs.BackgroundJob
- Perintah dan skrip berjalan dalam proses terpisah pada komputer lokal. Untuk informasi selengkapnya, lihat about_Jobs.PSTaskJob
atauThreadJob
- Perintah dan skrip berjalan dalam utas terpisah dalam proses yang sama pada komputer lokal.
Pekerjaan berbasis utas tidak sekuat pekerjaan jarak jauh dan latar belakang, karena berjalan dalam proses yang sama pada utas yang berbeda. Jika satu pekerjaan memiliki kesalahan kritis yang merusak proses, maka semua pekerjaan lain dalam proses dihentikan.
Namun, pekerjaan berbasis utas membutuhkan lebih sedikit overhead. Mereka tidak menggunakan lapisan jarak jauh atau serialisasi. Objek hasil dikembalikan sebagai referensi ke objek langsung dalam sesi saat ini. Tanpa overhead ini, pekerjaan berbasis utas berjalan lebih cepat dan menggunakan lebih sedikit sumber daya daripada jenis pekerjaan lainnya.
Penting
Sesi induk yang membuat pekerjaan juga memantau status pekerjaan dan mengumpulkan data alur. Proses turunan pekerjaan dihentikan oleh proses induk setelah pekerjaan mencapai status selesai. Jika sesi induk dihentikan, semua pekerjaan turunan yang berjalan dihentikan bersama dengan proses anak mereka.
Ada dua cara untuk mengatasi situasi ini:
- Gunakan
Invoke-Command
untuk membuat pekerjaan yang berjalan dalam sesi terputus. Untuk informasi selengkapnya, lihat about_Remote_Jobs. - Gunakan
Start-Process
untuk membuat proses baru daripada pekerjaan. Untuk informasi selengkapnya, lihat Proses Mulai.
Cara memulai dan mengelola pekerjaan berbasis utas
Ada dua cara untuk memulai pekerjaan berbasis utas:
Start-ThreadJob
- dari modul ThreadJobForEach-Object -Parallel -AsJob
- fitur paralel ditambahkan di PowerShell 7.0
Gunakan cmdlet Pekerjaan yang sama yang dijelaskan dalam about_Jobs untuk mengelola pekerjaan berbasis utas.
Menggunakan Start-ThreadJob
Modul ThreadJob pertama kali dikirim dengan PowerShell 6. Ini juga dapat diinstal dari Galeri PowerShell untuk Windows PowerShell 5.1.
Untuk memulai pekerjaan utas di komputer lokal, gunakan Start-ThreadJob
cmdlet dengan perintah atau skrip yang diapit kurung kurawal ({ }
).
Contoh berikut memulai pekerjaan utas Get-Process
yang menjalankan perintah di komputer lokal.
Start-ThreadJob -ScriptBlock { Get-Process }
Perintah Start-ThreadJob
mengembalikan ThreadJob
objek yang mewakili pekerjaan yang sedang berjalan. Objek pekerjaan berisi informasi yang berguna tentang pekerjaan termasuk status berjalan saat ini. Ini mengumpulkan hasil pekerjaan saat hasilnya dihasilkan.
Menggunakan ForEach-Object -Parallel -AsJob
PowerShell 7.0 menambahkan parameter baru yang diatur ke ForEach-Object
cmdlet. Parameter baru memungkinkan Anda menjalankan blok skrip dalam utas paralel sebagai pekerjaan PowerShell.
Anda dapat menyalurkan data ke ForEach-Object -Parallel
. Data diteruskan ke blok skrip yang dijalankan secara paralel. Parameter -AsJob
membuat objek pekerjaan untuk setiap utas paralel.
Perintah berikut memulai pekerjaan yang berisi pekerjaan anak untuk setiap nilai input yang disalurkan ke perintah . Setiap pekerjaan anak menjalankan Write-Output
perintah dengan nilai input yang disalurkan sebagai argumen.
1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob
Perintah ForEach-Object -Parallel
mengembalikan PSTaskJob
objek yang berisi pekerjaan anak untuk setiap nilai input yang disalurkan. Objek pekerjaan berisi informasi yang berguna tentang pekerjaan anak yang menjalankan status. Ini mengumpulkan hasil pekerjaan anak saat hasilnya dihasilkan.
Cara menunggu pekerjaan selesai dan mengambil hasil pekerjaan
Anda dapat menggunakan cmdlet pekerjaan PowerShell, seperti Wait-Job
dan Receive-Job
menunggu pekerjaan selesai lalu mengembalikan semua hasil yang dihasilkan oleh pekerjaan.
Perintah berikut memulai pekerjaan utas Get-Process
yang menjalankan perintah, lalu menunggu perintah selesai, dan akhirnya mengembalikan semua hasil data yang dihasilkan oleh perintah.
Start-ThreadJob -ScriptBlock { Get-Process } | Wait-Job | Receive-Job
Perintah berikut memulai pekerjaan yang menjalankan Write-Output
perintah untuk setiap input yang disalurkan, lalu menunggu semua pekerjaan turunan selesai, dan akhirnya mengembalikan semua hasil data yang dihasilkan oleh pekerjaan anak.
1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob | Wait-Job | Receive-Job
Receive-Job
Cmdlet mengembalikan hasil pekerjaan anak.
1
3
2
4
5
Karena setiap pekerjaan anak berjalan paralel, urutan hasil yang dihasilkan tidak dijamin.
Performa pekerjaan utas
Pekerjaan utas lebih cepat dan lebih ringan daripada jenis pekerjaan lainnya. Tetapi mereka masih memiliki overhead yang bisa besar jika dibandingkan dengan pekerjaan yang dilakukan pekerjaan.
PowerShell menjalankan perintah dan skrip dalam sesi. Hanya satu perintah atau skrip yang dapat berjalan pada satu waktu dalam sesi. Jadi saat menjalankan beberapa pekerjaan, setiap pekerjaan berjalan dalam sesi terpisah. Setiap sesi berkontribusi pada overhead.
Pekerjaan utas memberikan performa terbaik ketika pekerjaan yang mereka lakukan lebih besar dari overhead sesi yang digunakan untuk menjalankan pekerjaan. Ada dua kasus untuk yang memenuhi kriteria ini.
Pekerjaan bersifat komputasi intensif - Menjalankan skrip pada beberapa pekerjaan utas dapat memanfaatkan beberapa inti prosesor dan selesai lebih cepat.
Pekerjaan terdiri dari menunggu yang signifikan - Skrip yang menghabiskan waktu menunggu I/O atau hasil panggilan jarak jauh. Berjalan secara paralel biasanya selesai lebih cepat daripada jika dijalankan secara berurutan.
(Measure-Command {
1..1000 | ForEach { Start-ThreadJob { Write-Output "Hello $using:_" } } | Receive-Job -Wait
}).TotalMilliseconds
36860.8226
(Measure-Command {
1..1000 | ForEach-Object { "Hello: $_" }
}).TotalMilliseconds
7.1975
Contoh pertama di atas menunjukkan perulangan foreach yang membuat 1000 pekerjaan utas untuk melakukan penulisan string sederhana. Karena overhead pekerjaan, dibutuhkan lebih dari 36 detik untuk menyelesaikannya.
Contoh kedua menjalankan ForEach
cmdlet untuk melakukan 1000 operasi yang sama.
Kali ini, ForEach-Object
berjalan secara berurutan, pada satu utas, tanpa overhead pekerjaan apa pun. Ini selesai hanya dalam 7 milidetik.
Dalam contoh berikut, hingga 5000 entri dikumpulkan untuk 10 log sistem terpisah. Karena skrip melibatkan pembacaan sejumlah log, masuk akal untuk melakukan operasi secara paralel.
$logNames.count
10
Measure-Command {
$logs = $logNames | ForEach-Object {
Get-WinEvent -LogName $_ -MaxEvents 5000 2>$null
}
}
TotalMilliseconds : 252398.4321 (4 minutes 12 seconds)
$logs.Count
50000
Skrip selesai dalam setengah waktu ketika pekerjaan dijalankan secara paralel.
Measure-Command {
$logs = $logNames | ForEach {
Start-ThreadJob {
Get-WinEvent -LogName $using:_ -MaxEvents 5000 2>$null
} -ThrottleLimit 10
} | Wait-Job | Receive-Job
}
TotalMilliseconds : 115994.3 (1 minute 56 seconds)
$logs.Count
50000
Pekerjaan dan variabel utas
Ada beberapa cara untuk meneruskan nilai ke dalam pekerjaan berbasis utas.
Start-ThreadJob
dapat menerima variabel yang disalurkan ke cmdlet, diteruskan ke blok skrip melalui $using
kata kunci, atau diteruskan melalui parameter ArgumentList .
$msg = "Hello"
$msg | Start-ThreadJob { $input | Write-Output } | Wait-Job | Receive-Job
Start-ThreadJob { Write-Output $using:msg } | Wait-Job | Receive-Job
Start-ThreadJob { param ([string] $message) Write-Output $message } -ArgumentList @($msg) |
Wait-Job | Receive-Job
ForEach-Object -Parallel
menerima pipa dalam variabel, dan variabel yang diteruskan langsung ke blok skrip melalui $using
kata kunci.
$msg = "Hello"
$msg | ForEach-Object -Parallel { Write-Output $_ } -AsJob | Wait-Job | Receive-Job
1..1 | ForEach-Object -Parallel { Write-Output $using:msg } -AsJob | Wait-Job | Receive-Job
Karena pekerjaan utas berjalan dalam proses yang sama, jenis referensi variabel apa pun yang diteruskan ke pekerjaan harus diperlakukan dengan hati-hati. Jika itu bukan objek aman utas, maka itu tidak boleh ditetapkan, dan metode dan properti tidak boleh dipanggil di atasnya.
Contoh berikut meneruskan objek .NET ConcurrentDictionary
aman utas ke semua pekerjaan anak untuk mengumpulkan objek proses bernama unik. Karena ini adalah objek aman utas, itu dapat digunakan dengan aman saat pekerjaan berjalan bersamaan dalam proses.
$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
$jobs = Get-Process | ForEach {
Start-ThreadJob {
$proc = $using:_
$dict = $using:threadSafeDictionary
$dict.TryAdd($proc.ProcessName, $proc)
}
}
$jobs | Wait-Job | Receive-Job
$threadSafeDictionary.Count
96
$threadSafeDictionary["pwsh"]
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
112 108.25 124.43 69.75 16272 1 pwsh