Konu İşleri hakkında
Kısa açıklama
PowerShell iş parçacığı tabanlı işler hakkında bilgi sağlar. İş parçacığı işi, geçerli oturum işleminde ayrı bir iş parçacığında bir komut veya ifadeyi çalıştıran bir tür arka plan işidir.
Uzun açıklama
PowerShell, işler aracılığıyla komutları ve komut dosyalarını aynı anda çalıştırır. Eşzamanlılığı desteklemek için PowerShell tarafından sağlanan üç iş türü vardır.
RemoteJob- Komutlar ve komut dosyaları uzak bir oturumda çalıştırılır. Bilgi için bkz. about_Remote_Jobs.BackgroundJob- Komutlar ve komut dosyaları, yerel makinede ayrı bir işlemde çalıştırılır. Daha fazla bilgi için bkz. about_Jobs.PSTaskJobveyaThreadJob- Komutlar ve komut dosyaları, yerel makinede aynı işlem içinde ayrı bir iş parçacığında çalıştırılır.
İş parçacığı tabanlı işler, farklı iş parçacıklarında aynı süreçte çalıştıkları için uzak ve arka plan işleri kadar sağlam değildir. Bir işte, süreci çökerten kritik bir hata varsa, süreçteki diğer tüm işler sonlandırılır.
Ancak iş parçacığı tabanlı işler daha az ek yük gerektirir. Uzaktan iletişim katmanını veya serileştirmeyi kullanmazlar. Sonuç nesneleri, geçerli oturumdaki canlı nesnelere referans olarak döndürülür. Bu ek yük olmadan iş parçacığı tabanlı işler diğer iş türlerine göre daha hızlı çalışır ve daha az kaynak kullanır.
Bu önemli
İşi oluşturan üst oturum aynı zamanda iş durumunu izler ve ardışık düzen verilerini toplar. İş bitmiş duruma ulaştığında, iş alt süreci ana süreç tarafından sonlandırılır. Ana oturum sonlandırılırsa çalışan tüm alt işler, alt süreçleriyle birlikte sonlandırılır.
Bu durumu çözmenin iki yolu vardır:
- Bağlantısı olmayan oturumlarda çalışan işler oluşturmak için
Invoke-Command'ı kullanın. Daha fazla bilgi için bkz. about_Remote_Jobs. - Bir iş yerine yeni bir süreç oluşturmak için
İşlemi Başlat'ı kullanın. Daha fazla bilgi için bkz. İşlem Başlatma.
İş parçacığı tabanlı işler nasıl başlatılır ve yönetilir
İş parçacığı tabanlı işleri başlatmanın iki yolu vardır:
Start-ThreadJob- ThreadJob modülündenForEach-Object -Parallel -AsJob- PowerShell 7,0'a paralel özellik eklendi
İş parçacığı tabanlı işleri yönetmek için about_Jobs'ta açıklanan aynı İş cmdlet'lerini kullanın.
Start-ThreadJob'u kullanma
ThreadJob modülü ilk olarak PowerShell 6 ile birlikte gönderildi. Ayrıca Windows PowerShell 5.1 için PowerShell Galerisinden de yüklenebilir.
Yerel bilgisayarda bir iş parçacığı işi başlatmak için Start-ThreadJob cmdlet'ini küme parantezleri ({ ) içine alınmış bir komut veya komut dosyasıyla birlikte kullanın.
Aşağıdaki örnek, yerel bilgisayarda Get-Process komutunu çalıştıran bir iş parçacığı işini başlatır.
Start-ThreadJob -ScriptBlock { Get-Process }
Start-ThreadJob komutu, çalışan işi temsil eden bir ThreadJob nesnesini döndürür. İş nesnesi, mevcut çalışma durumu da dahil olmak üzere iş hakkında yararlı bilgiler içerir. Sonuçlar üretilirken işin sonuçlarını toplar.
ForEach-Object -Parallel -AsJob'u kullanma
PowerShell 7.0, ForEach-Object cmdlet'ine yeni bir parametre kümesi ekledi. Yeni parametreler, betik bloklarını PowerShell işleri olarak paralel iş parçacıklarında çalıştırmanıza olanak tanır.
Verileri ForEach-Object -Parallel'e aktarabilirsiniz. Veriler paralel olarak çalıştırılan komut dosyası bloğuna aktarılır. -AsJob parametresi paralel iş parçacıklarının her biri için iş nesneleri oluşturur.
Aşağıdaki komut, komuta iletilen her giriş değeri için alt işleri içeren bir işi başlatır. Her alt iş, bağımsız değişken olarak aktarılan bir giriş değeriyle Write-Output komutunu çalıştırır.
1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob
ForEach-Object -Parallel komutu, aktarılan her giriş değeri için alt işleri içeren bir PSTaskJob nesnesi döndürür. İş nesnesi, alt işlerin çalışma durumu hakkında yararlı bilgiler içerir. Sonuçlar üretilirken alt işlerin sonuçlarını toplar.
Bir işin tamamlanması ve iş sonuçlarının alınması nasıl beklenir?
Bir işin tamamlanmasını beklemek ve ardından iş tarafından oluşturulan tüm sonuçları döndürmek için Wait-Job ve Receive-Job gibi PowerShell iş cmdlet'lerini kullanabilirsiniz.
Aşağıdaki komut, Get-Process komutunu çalıştıran bir iş parçacığı işi başlatır, ardından komutun tamamlanmasını bekler ve son olarak komut tarafından oluşturulan tüm veri sonuçlarını döndürür.
Start-ThreadJob -ScriptBlock { Get-Process } | Wait-Job | Receive-Job
Aşağıdaki komut, aktarılan her giriş için Yazma-Çıktı komutunu çalıştıran bir işi başlatır, ardından tüm alt işlerin tamamlanmasını bekler ve son olarak alt işler tarafından oluşturulan tüm veri sonuçlarını döndürür.
1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob | Wait-Job | Receive-Job
Receive-Job cmdlet'i alt işlerin sonuçlarını döndürür.
1
3
2
4
5
Her alt iş paralel çalıştığı için oluşturulan sonuçların sırası garanti edilmez.
İş parçacığı işi performansı
İplik işleri diğer iş türlerine göre daha hızlı ve daha hafiftir. Ancak işin yaptığı işle karşılaştırıldığında hala büyük olabilecek ek yükleri var.
PowerShell, bir oturumda komutları ve betiği çalıştırır. Bir oturumda aynı anda yalnızca bir komut veya komut dosyası çalıştırılabilir. Yani birden fazla iş çalıştırıldığında her iş ayrı bir oturumda çalışır. Her oturum genel gidere katkıda bulunur.
İş parçacığı işleri, gerçekleştirdikleri iş, işi yürütmek için kullanılan oturumun ek yükünden daha büyük olduğunda en iyi performansı sağlar. Bu kriterleri karşılayan iki durum vardır.
-
İş yoğun bilgi işlem gerektirir - Bir komut dosyasını birden çok iş parçacığı işinde çalıştırmak, birden çok işlemci çekirdeğinden yararlanabilir ve işlemi daha hızlı tamamlayabilir.
İş, önemli miktarda beklemeden oluşur - G/Ç veya uzaktan çağrı sonuçlarını beklerken zaman harcayan bir komut dosyası. Paralel olarak çalıştırmak genellikle sıralı çalıştırmaya göre daha hızlı tamamlanır.
(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
Yukarıdaki ilk örnekte, basit bir dize yazma işlemi gerçekleştirmek için 1000 iş parçacığı işi oluşturan bir foreach döngüsü gösterilmektedir. İşin genel giderlerinden dolayı tamamlanması 36 saniyeden fazla sürüyor.
İkinci örnek, aynı 1000 işlemi gerçekleştirmek için ForEach cmdlet'ini çalıştırır. Bu sefer ForEach-Object herhangi bir iş yükü olmadan tek bir iş parçacığı üzerinde sırayla çalışıyor. Sadece 7 milisaniyede tamamlanıyor.
Aşağıdaki örnekte, 10 ayrı sistem günlüğü için 5000'e kadar giriş toplanmıştır. Komut dosyası bir dizi günlüğün okunmasını içerdiğinden, işlemleri paralel olarak yapmak mantıklıdır.
$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
İşler paralel olarak çalıştırıldığında komut dosyası yarı sürede tamamlanır.
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
İş parçacığı işleri ve değişkenler
Değerleri iş parçacığı tabanlı işlere aktarmanın birden fazla yolu vardır.
Start-ThreadJob, cmdlet'e aktarılan, $using anahtar sözcüğü aracılığıyla komut dosyası bloğuna iletilen veya ArgumentList parametre.
$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, aktarılan değişkenleri ve $using anahtar sözcüğü aracılığıyla doğrudan komut dosyası bloğuna iletilen değişkenleri kabul eder.
$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
İş parçacığı işleri aynı süreçte çalıştığından, işe aktarılan herhangi bir değişken referans türünün dikkatli bir şekilde ele alınması gerekir. İş parçacığı açısından güvenli bir nesne değilse, o zaman ona hiçbir zaman atanmamalı ve yöntem ve özellikler hiçbir zaman onun üzerinde çağrılmamalıdır.
Aşağıdaki örnek, benzersiz şekilde adlandırılmış işlem nesnelerini toplamak için iş parçacığı açısından güvenli bir .NET ConcurrentDictionary nesnesini tüm alt işlere geçirir. İş parçacığı açısından güvenli bir nesne olduğundan, süreç içinde işler eş zamanlı olarak yürütülürken güvenle kullanılabilir.
$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
Ayrıca bakınız
- about_Job_Details
- about_Remote_Jobs
- about_Thread_Jobs
- about_PSSessions
- about_Remote
- Get-Job
- Receive-Job
- Remove-Job
- Start-Job
- Stop-Job
- Wait-Job