about_Thread_Jobs

Rövid leírás

Információt nyújt a PowerShell-szálalapú feladatokról. A szálfeladatok olyan háttérfeladatok, amelyek egy parancsot vagy kifejezést futtatnak egy külön szálon az aktuális munkamenet-folyamaton belül.

Hosszú leírás

A PowerShell egyszerre futtat parancsokat és szkripteket a feladatokon keresztül. A PowerShell három feladattípust biztosít az egyidejűség támogatásához.

  • RemoteJob - A parancsok és szkriptek távoli munkamenetben futnak. További információ: about_Remote_Jobs.
  • BackgroundJob – A parancsok és szkriptek külön folyamaton futnak a helyi gépen. További információkért lásd a feladatokat ismertető szakaszt.
  • PSTaskJob vagy ThreadJob – A parancsok és szkriptek külön szálon futnak ugyanazon a folyamaton belül a helyi gépen.

A szálalapú feladatok nem olyan robusztusak, mint a távoli és a háttérfeladatok, mivel ugyanabban a folyamatban futnak különböző szálakon. Ha egy feladat kritikus hibát jelez, amely összeomlik a folyamat során, akkor a folyamat összes többi feladata leáll.

A szálalapú feladatok azonban kevesebb többletterhelést igényelnek. Nem használják az átnevezési réteget vagy a szerializálást. Az eredményobjektumok az aktuális munkamenetben élő objektumokra mutató hivatkozásokként jelennek meg. E többletterhelés nélkül a szálalapú feladatok gyorsabban futnak, és kevesebb erőforrást használnak, mint a többi feladattípus.

Fontos

A feladatot létrehozó szülő munkamenet is figyeli a feladat állapotát, és összegyűjti a folyamatadatokat. A feladat gyermekfolyamatát a szülőfolyamat leállítja, amint a feladat befejeződött. Ha a szülő munkamenet le van állítva, a rendszer az összes futó gyermekfeladatot leállítja a gyermekfolyamatokkal együtt.

Kétféleképpen lehet megkerülni ezt a helyzetet:

  1. Leválasztott munkamenetekben futó feladatok létrehozásához használható Invoke-Command . További információ: about_Remote_Jobs.
  2. Feladat Start-Process helyett új folyamatot hozhat létre. További információ: Start-Process.

Szálalapú feladatok indítása és kezelése

A szálalapú feladatok kétféleképpen indíthatóak el:

  • Start-ThreadJob - a ThreadJob modulból
  • ForEach-Object -Parallel -AsJob - a párhuzamos funkció a PowerShell 7.0-s verzióban lett hozzáadva

A szálalapú feladatok kezeléséhez használja az about_Jobs ismertetett feladatparancsmagokat.

Az Start-ThreadJob használata

A ThreadJob modult először a PowerShell 6-tal szállították le. A Windows PowerShell 5.1 PowerShell-galéria is telepíthető.

Ha egy szálfeladatot szeretne elindítani a helyi számítógépen, használja a Start-ThreadJob parancsmagot egy kapcsos zárójelek ({ }) közé zárt paranccsal vagy szkripttel.

Az alábbi példa elindít egy szálfeladatot, amely parancsot Get-Process futtat a helyi számítógépen.

Start-ThreadJob -ScriptBlock { Get-Process }

A Start-ThreadJob parancs egy ThreadJob , a futó feladatot jelképező objektumot ad vissza. A feladatobjektum hasznos információkat tartalmaz a feladatról, beleértve annak aktuális futó állapotát is. Összegyűjti a feladat eredményeit az eredmények létrehozásakor.

Az ForEach-Object -Parallel -AsJob használata

A PowerShell 7.0 új paraméterkészletet adott hozzá a ForEach-Object parancsmaghoz. Az új paraméterek lehetővé teszik a szkriptblokkok párhuzamos szálakban való futtatását PowerShell-feladatokként.

Az adatokat a parancsra helyezheti.ForEach-Object -Parallel Az adatok a párhuzamosan futó szkriptblokkba kerülnek. A -AsJob paraméter feladatobjektumokat hoz létre az egyes párhuzamos szálakhoz.

Az alábbi parancs elindít egy feladatot, amely gyermekfeladatokat tartalmaz a parancshoz csövezott minden bemeneti értékhez. Minden gyermekfeladat egy vezetékes bemeneti értékkel futtatja a Write-Output parancsot argumentumként.

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

A ForEach-Object -Parallel parancs egy PSTaskJob olyan objektumot ad vissza, amely gyermekfeladatokat tartalmaz minden egyes vezetékes bemeneti értékhez. A feladatobjektum hasznos információkat tartalmaz a futó gyermekfeladatokról. Összegyűjti a gyermekfeladatok eredményeit az eredmények létrehozásakor.

A feladatok befejezésére és a feladatok eredményeinek lekérésére való várakozás

A PowerShell-feladat parancsmagjaival például Wait-JobReceive-Job megvárhatja, amíg egy feladat befejeződik, majd visszaadhatja a feladat által létrehozott összes eredményt.

A következő parancs elindít egy parancsot futtató Get-Process szálfeladatot, majd megvárja a parancs befejezését, és végül visszaadja a parancs által generált összes adateredményt.

Start-ThreadJob -ScriptBlock { Get-Process } | Wait-Job | Receive-Job

A következő parancs elindít egy feladatot, amely parancsot Write-Output futtat minden egyes vezetékes bemenethez, majd megvárja, amíg az összes gyermekfeladat befejeződik, és végül visszaadja a gyermekfeladatok által generált összes adateredményt.

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

A Receive-Job parancsmag a gyermekfeladatok eredményeit adja vissza.

1
3
2
4
5

Mivel minden gyermekfeladat párhuzamosan fut, a létrehozott eredmények sorrendje nem garantált.

Szálfeladat teljesítménye

A szálfeladatok gyorsabbak és könnyebbek, mint más típusú feladatok. De még mindig vannak olyan többletterheléseik, amelyek nagyok lehetnek, ha összehasonlítják a munkát.

A PowerShell parancsokat és szkripteket futtat egy munkamenetben. Egy munkamenetben egyszerre csak egy parancs vagy szkript futtatható. Így több feladat futtatásakor minden feladat külön munkamenetben fut. Minden munkamenet hozzájárul a többletterheléshez.

A szálfeladatok akkor biztosítják a legjobb teljesítményt, ha az általuk végzett munka nagyobb, mint a feladat futtatásához használt munkamenet többletterhelése. Két eset felel meg ennek a feltételnek.

  • A munka nagy számítási igényű – A szkriptek több szálas feladaton való futtatása több processzormag előnyeit is kihasználhatja, és gyorsabban elvégezhető.

  • A munka jelentős várakozásból áll – Egy szkript, amely időt tölt az I/O vagy a távoli hívás eredményeire való várakozással. A párhuzamos futtatás általában gyorsabb, mint ha egymás után fut.

(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

A fenti első példa egy foreach hurkot mutat be, amely 1000 szálfeladatot hoz létre egy egyszerű sztring írásához. A feladat többletterhelése miatt több mint 36 másodpercet vesz igénybe.

A második példa futtatja a ForEach parancsmagot, hogy ugyanazt az 1000 műveletet hajtsa végre. Ezúttal ForEach-Object egymás után, egyetlen szálon fut, feladatterhelés nélkül. Ez 7 ezredmásodpercben fejeződik be.

Az alábbi példában legfeljebb 5000 bejegyzést gyűjtünk össze 10 különálló rendszernaplóhoz. Mivel a szkript több napló olvasását is magában foglalja, érdemes párhuzamosan elvégezni a műveleteket.

$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

A szkript a feladatok párhuzamos futtatásának félidejében fejeződik be.

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

Szálfeladatok és változók

Az értékeket többféleképpen is átadhatja a szálalapú feladatoknak.

Start-ThreadJob A parancsmagra csövezett, a szkriptblokkba a kulcsszón keresztül $using átadott vagy az ArgumentList paraméteren keresztül átadott változókat is elfogadhatja.

$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 Változókba csövezve fogadja el, és a szkriptblokknak közvetlenül a kulcsszón keresztül $using átadott változókat.

$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

Mivel a szálfeladatok ugyanabban a folyamatban futnak, a feladatba átadott változó referenciatípusokat gondosan kell kezelni. Ha nem szálbiztos objektum, akkor soha nem szabad hozzárendelni, és a metódust és a tulajdonságokat soha nem kell meghívni rajta.

Az alábbi példa egy szálbiztos .NET-objektumot ConcurrentDictionary ad át az összes gyermekfeladatnak, hogy egyedileg elnevezett folyamatobjektumokat gyűjtsön. Mivel ez egy szálbiztos objektum, biztonságosan használható, miközben a feladatok párhuzamosan futnak a folyamatban.

$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

Lásd még