Aracılığıyla paylaş


hakkında_Tread_Görevleri

Kısa açıklama

PowerShell iş parçacığı tabanlı işler hakkında bilgi sağlar. İş parçacığı işi, geçerli oturum işlemi içinde ayrı bir iş parçacığında bir komut veya ifade çalıştıran bir arka plan işi türüdür.

Uzun açıklama

PowerShell, komutları ve betikleri görevler aracılığıyla eşzamanlı olarak çalıştırır. Eşzamanlılığı desteklemek için PowerShell tarafından sağlanan üç iş türü vardır.

  • RemoteJob - Komutlar ve betikler uzak oturumda çalışır. Bilgi için bkz. about_Remote_Jobs.
  • BackgroundJob - Komutlar ve betikler yerel makinede ayrı bir işlemde çalıştırılır. Daha fazla bilgi için bkz. about_Jobs.
  • PSTaskJob veya ThreadJob - Komutlar ve betikler, yerel makinede aynı işlem içinde ayrı bir iş parçacığında çalışır.

İş parçacığı tabanlı işler, farklı iş parçacıklarında aynı işlem üzerinde çalıştırıldıkları için, sağlamlık bakımından uzak ve arka plan işleri kadar güçlü değildir. Bir işin işlemi kilitleyen kritik bir hatası varsa, işlemdeki diğer tüm işler sonlandırılır.

Ancak iş parçacığı tabanlı işler daha az ek yük gerektirir. Uzaktan erişim katmanını veya serileştirmeyi kullanmazlar. Sonuç nesneleri geçerli oturumdaki canlı nesnelere başvuru olarak döndürülür. Bu ek yük olmadan, iş parçacığı tabanlı işler daha hızlı çalışır ve diğer iş türlerinden daha az kaynak kullanır.

Önemli

İşi oluşturan üst oturum da iş durumunu izler ve işlem hattı verilerini toplar. İş tamamlanmış duruma ulaştığında, iş alt işlemi üst işlem tarafından sonlandırılır. Ebeveyn oturum sonlandırılırsa, çalışan tüm alt işler kendi alt işlemleriyle birlikte sonlandırılır.

Bu durumu geçici olarak gidermenin iki yolu vardır:

  1. bağlantısız oturumlarda çalışan işler oluşturmak için Invoke-Command kullanın. Daha fazla bilgi için bkz. about_Remote_Jobs.
  2. Bir iş (job) yerine yeni bir işlem oluşturmak için Start-Process kullanın. Daha fazla bilgi için bkz. başlangıç-işlem.

İş parçacığı tabanlı işleri başlatma ve yönetme

İş parçacığı tabanlı işleri başlatmanın iki yolu vardır:

  • Start-ThreadJob - ThreadJob modülünden
  • ForEach-Object -Parallel -AsJob - Paralel özellik PowerShell 7.0'a eklendi

İş parçacığı tabanlı işleri yönetmek için, about_Jobs'de açıklanan İş cmdlet'leri kullanın.

Start-ThreadJob kullanma

ThreadJob modülü ilk olarak PowerShell 6 ile birlikte gönderilir. Windows PowerShell 5.1 için PowerShell Galerisi'nden de yüklenebilir.

Yerel bilgisayarda bir alt görev başlatmak için Start-ThreadJob cmdlet'ini süslü parantez ({ }) içine alınmış bir komut veya betik ile kullanın.

Aşağıdaki örnek, yerel bilgisayarda bir Get-Process komutu çalıştıran bir iş parçacığı başlatır.

Start-ThreadJob -ScriptBlock { Get-Process }

Start-ThreadJob komutu, çalışmakta olan işi temsil eden bir ThreadJob nesnesi döndürür. İş nesnesi, geçerli çalışma durumu da dahil olmak üzere iş hakkında yararlı bilgiler içerir. Sonuçlar oluşturulurken işin sonuçlarını toplar.

ForEach-Object -Parallel -AsJob kullanma

PowerShell 7.0, ForEach-Object cmdlet'ine yeni bir parametre kümesi ekledi. Yeni parametreler, paralel iş parçacıklarında betik bloklarını PowerShell işleri olarak çalıştırmanıza olanak tanır.

ForEach-Object -Parallel'e veri kanal oluşturabilirsiniz. Veriler paralel olarak çalıştırılacak betik bloğuna geçirilir. -AsJob parametresi, paralel iş parçacıklarının her biri için iş nesneleri oluşturur.

Aşağıdaki komut, komutuna yöneltilen her giriş değeri için alt işleri içeren bir iş başlatır. Her bir alt iş, birleştirilmiş giriş değeri bağımsız değişken olarak Write-Output komutunu çalıştırır.

1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob

ForEach-Object -Parallel komutu, her kanallı 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 oluşturulurken, eş zamanlı olarak alt işlerin sonuçlarını toplar.

bir işin tamamlanmasını bekleme ve iş sonuçlarını alma

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, bir Get-Process komutu ç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, kanallı her giriş için bir Write-Output komutu çalıştıran bir 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 alt işlerin sonuçlarını döndürür.

1
3
2
4
5

Her bir alt iş paralel çalıştığından, oluşturulan sonuçların sırası garanti edilmez.

İş parçacığı işi performansı

İş parçacığı görevleri, diğer görev türlerine göre daha hızlı ve daha hafiftir. Ancak yine de işin yaptığı işe kıyasla büyük olabilecek ek yükleri vardır.

PowerShell bir oturumda komut ve betik çalıştırır. Oturumda aynı anda yalnızca bir komut veya betik çalıştırılabilir. Bu nedenle, birden çok iş çalıştırıldığında, her biri ayrı bir oturumda çalışır. Her oturum ek yüke katkıda bulunur.

İş parçacığı işleri, gerçekleştirdikleri iş işi çalıştırmak için kullanılan oturumun yükünden fazla olduğunda en iyi performansı sağlar. Bu ölçüte uyan iki durum vardır.

  • İş, yüksek işlem gücü gerektiriyor - Bir betiği birden çok iş parçacığında çalıştırmak, işlemci çekirdeklerini daha verimli şekilde kullanır ve daha hızlı tamamlanmasını sağlar.

  • Çalışma, önemli miktarda beklemeden oluşur: G/Ç veya uzaktan arama sonuçlarını beklerken zaman harcayan bir betik. Paralel çalıştırma genellikle sıralı olarak çalıştırıldığından daha hızlı tamamlar.

(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 yapmak için 1000 iş parçacığı işi oluşturan bir foreach döngüsü gösterilmektedir. İş yükü nedeniyle tamamlanması 36 saniyeden fazla sürer.

İkinci örnek, aynı 1000 işlemi yapmak için ForEach-Object cmdlet'ini çalıştırır. Bu kez, ForEach-Object herhangi bir iş yükü olmadan tek bir iş parçacığında sıralı olarak çalışır. Yalnızca 7 milisaniye içinde tamamlar.

Aşağıdaki örnekte, 10 ayrı sistem günlüğü için en fazla 5000 girdi toplanır. Betik bir dizi log dosyasını okumayı içerdiğinden, işlemleri paralel bir şekilde yürütmek 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

Betik, işler paralel olarak çalıştırıldığında yarı sürede tamamlanıyor.

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

İş parçacığı tabanlı işlere değer geçirmenin birden çok yolu vardır.

Start-ThreadJob cmdlet'ine kanalize edilen, kapsam değiştirici aracılığıyla Using: betik bloğuna geçirilen veya ArgumentList parametresi aracılığıyla geçirilen değişkenleri kabul edebilir.

$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 değişkenleri ve kapsam değiştirici aracılığıyla Using: doğrudan scriptblock'a geçirilen 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ı işlemde çalıştırıldığından, işe geçirilen tüm değişken başvuru türlerinin dikkatli bir şekilde ele alınması gerekir. İş parçacığı güvenli bir nesne değilse, asla atanmamalı ve üzerinde hiçbir zaman yöntem ve özellik çağrılmamalıdır.

Benzersiz adlandırılmış işlem nesnelerini toplamak için iş parçacığı açısından güvenli bir .NET ConcurrentDictionary nesnesi, aşağıdaki örnekte tüm alt işlere aktarılır. İş parçacığı güvenli bir nesne olduğundan, işlem aynı anda devam ederken güvenli bir şekilde 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