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 atau ThreadJob - 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:

  1. Gunakan Invoke-Command untuk membuat pekerjaan yang berjalan dalam sesi terputus. Untuk informasi selengkapnya, lihat about_Remote_Jobs.
  2. 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 ThreadJob
  • ForEach-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

Lihat juga