Aracılığıyla paylaş


about_Thread_Jobs

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 işler 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. İşler hakkında.
  • PSTaskJob or 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şlemde çalıştırıldığından uzak ve arka plan işleri kadar sağlam 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 iletişim katmanını veya serileştirmeyi kullanmaz. 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. Üst 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 kullanın Invoke-Command . Daha fazla bilgi için bkz . about_Remote_Jobs.
  2. İş yerine yeni bir işlem oluşturmak için kullanın Start-Process . Daha fazla bilgi için bkz . Start-Process.

İş 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 aynı İş cmdlet'lerini kullanın.

Start-ThreadJob kullanma

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

Yerel bilgisayarda bir iş parçacığı işi başlatmak için, cmdlet'ini Start-ThreadJob küme ayraçları ({ } içine alınmış bir komut veya betikle kullanın.

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

Start-ThreadJob -ScriptBlock { Get-Process }

komutu, Start-ThreadJob çalışan işi temsil eden bir ThreadJob nesne 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 cmdlet'ine ForEach-Object yeni bir parametre kümesi ekledi. Yeni parametreler, powershell işleri olarak paralel iş parçacıklarında betik bloklarını çalıştırmanıza olanak tanır.

Verileri adresine ForEach-Object -Parallelyöneltebilirsiniz. Veriler paralel olarak çalıştırılacak betik bloğuna geçirilir. parametresi, -AsJob 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 alt iş, Write-Output bağımsız değişken olarak bir kanallı giriş değeriyle komutunu çalıştırır.

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

komutu, ForEach-Object -Parallel her kanallı giriş değeri için alt işleri içeren bir PSTaskJob nesne döndürür. İş nesnesi, alt işlerin çalışma durumu hakkında yararlı bilgiler içerir. Sonuçlar oluşturulurken alt işlerin sonuçlarını toplar.

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

ve gibi Wait-Job Receive-Job PowerShell iş cmdlet'lerini kullanarak bir işin tamamlanmasını bekleyebilir ve ardından iş tarafından oluşturulan tüm sonuçları döndürebilirsiniz.

Aşağıdaki komut bir komut çalıştıran bir Get-Process 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, her kanallı giriş için bir komut çalıştıran bir Write-Output 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

Cmdlet, Receive-Job alt işlerin sonuçlarını döndürür.

1
3
2
4
5

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

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

İş parçacığı işleri, diğer iş 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ırken her iş 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.

  • İş yoğun işlem gücü kullanıyor - Birden çok iş parçacığı işinde betik çalıştırmak, birden çok işlemci çekirdeğinden yararlanabilir ve daha hızlı tamamlanabilir.

  • Ç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 cmdlet'ini çalıştırır ForEach . 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 birkaç günlük okumayı 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

Betik, işlerin paralel olarak çalıştırıldığında yarı yarıya 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-ThreadJobcmdlet'ine kanalize edilen, anahtar sözcüğü 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 anahtar sözcüğü aracılığıyla $using doğrudan betik bloğuna 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, hiçbir zaman atanmamalıdır ve yöntem ve özellikler hiçbir zaman üzerinde çağrılmamalıdır.

Aşağıdaki örnek, benzersiz olarak 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ığı güvenli bir nesne olduğundan, işler işlemde eşzamanlı olarak çalışırken 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 bkz.