Háttérben futtatás egy alternatív módja

Az előző fejezetben látott „job”-ok, bár nagyon kényelmesen használhatók a kapcsolódó cmdletek segíségével, mégis rendelkeznek néhány hátrányos tulajdonsággal:

Létrehozásuk viszonylag lassú, így csak akkor éri meg a használatuk, ha egy-egy job tényleg hosszú ideig fut. Ha sok rövid job-ot akarunk futtatni, akkor a „hasznos teher” feldolgozására fordított idő kevesebb lehet, mint maguknak a joboknak a létrehozása.

A job kimenete szerializáláson esik keresztül, azaz a bonyolult objektumok tulajdonságai egy rekurzív eljárással a háttérben XML dokumentummá alakulnak át, melyek a globális scope-ban visszaalakulnak objektummá (deszerializálás). Miután az XML nem egy nagyon tömör adattárolási módszer, ezért ha sok objektum van a kimenetben, akkor ez a folyamat is elég időigényes lehet.

Jó hír, hogy a [powershell] osztály felhasználásával a háttérben futtatás egy alternatív módját is használhatjuk. Rögtön mérjük is le a hagyományos job-ok és az elternatív módszer sebességének különbségét!

Az első szkriptben létrehozok 10 hagyományos job-ot, ami valójában egy Get-Process cmdletet futtat. Most, miután a $parameters a 4. sorban az éppen futó PowerShell folyamatra szűr, ezért a háttérben futó folyamat csak egy processz objektumot ad vissza.

$script = New-Object -TypeName object[] -ArgumentList 10

$output = New-Object -TypeName object[] -ArgumentList 10

$job = New-Object -TypeName object[] -ArgumentList 10

$parameters = "-id $pid"

#$parameters = ""

 

$start = Get-Date

for($i = 0; $i -lt 10; $i++){

    Write-Host "Creating job $i"

    $script[$i] = [scriptblock]::create("Get-Process $parameters; ""Thread $i""")

    $job[$i] = Start-Job -ScriptBlock $script[$i]

}

 

$createend = Get-Date

$creationtime = ($createend - $start).Totalseconds

write-host "Létrehozás tartott: $creationtime mp"

 

do {

    $stillrunning = $false

    Start-Sleep -Milliseconds 100

    for($i = 0; $i -lt 10; $i++){

        if($job[$i]){

            if($job[$i].state -eq "Completed"){

                $output[$i] = Receive-Job -Job $job[$i]

                Remove-Job -Job $job[$i]

                $job[$i] = $null

            }

            else{

                $stillrunning = $true

            }

        }

    }

} while ($stillrunning)

 

$executiontime = ((Get-Date) - $createend).Totalseconds

write-host "Futtatás tartott ($parameters): $executiontime mp"

Nézzük futtatásának eredményét:

PS C:\> . C:\PSKönyv\Realjobs.ps1

Creating job 0

Creating job 1

Creating job 2

Creating job 3

Creating job 4

Creating job 5

Creating job 6

Creating job 7

Creating job 8

Creating job 9

Létrehozás tartott: 3.0151724 mp

Futtatás tartott (-id 6292): 2.5181441 mp

Látható, hogy a 10 job létrehozása kb. 3 másodpercig tartott és futtatásuk csak 1-1-processz objektummal kb. 2.5 másodpercig.

Az $output tömbbe gyűjtött processz objektumok típusa a szerializálás-deszerializálás után így néz ki:

PS C:\> $output[0][0].pstypenames[0]

Deserialized.System.Diagnostics.Process

Ha kiveszem a kommentet az 5. sorból és berakom a 4. sor elejére, akkor az összes processz kilistázásra kerül. A futási idők ezzel így alakulnak:

PS C:\> C:\PSKönyv\Realjobs.ps1

Creating job 0

Creating job 1

Creating job 2

Creating job 3

Creating job 4

Creating job 5

Creating job 6

Creating job 7

Creating job 8

Creating job 9

Létrehozás tartott: 3.3111893 mp

Futtatás tartott (): 9.5175444 mp

Látható, hogy így a job-ok futtatása, a sokkal nagyobb kimenetnek köszönhetően sokkal több, kb. négyszer annyi ideig tartott, ez a szerializálás-deszerializálás számlájára írható.

Nézzük ugyanezt a szkriptet az alternatív módon:

$script = New-Object -TypeName object[] -ArgumentList 10

$thread = New-Object -TypeName object[] -ArgumentList 10

$output = New-Object -TypeName object[] -ArgumentList 10

$job = New-Object -TypeName object[] -ArgumentList 10

$parameters = "-id $pid"

#$parameters = ""

 

$start = Get-Date

for($i = 0; $i -lt 10; $i++){

    Write-Host "Creating job $i"

    $script[$i] = [scriptblock]::create("Get-Process $parameters; ""Thread $i""")

    $thread[$i] = [powershell]::Create()

    [void] $thread[$i].AddScript($script[$i])

    $job[$i] = $thread[$i].BeginInvoke()

}

 

$createend = Get-Date

$creationtime = ($createend - $start).Totalseconds

write-host "Létrehozás tartott: $creationtime mp"

 

do {

    $stillrunning = $false

    Start-Sleep -Milliseconds 100

    for($i = 0; $i -lt 10; $i++){

        if($job[$i]){

            if($job[$i].IsCompleted){

                $output[$i] = $thread[$i].EndInvoke($job[$i])

                $thread[$i].Runspace.Close()

                $thread[$i].Dispose()

                $job[$i] = $null

            }

            else{

                $stillrunning = $true

            }

        }

    }

} while ($stillrunning)

 

$executiontime = ((Get-Date) - $createend).Totalseconds

write-host "Futtatás tartott ($parameters): $executiontime mp"

 És a futtatási eredmények, először egy processzel:

PS C:\> . C:\PSKönyv\Alternatívjobs.ps1

Creating job 0

Creating job 1

Creating job 2

Creating job 3

Creating job 4

Creating job 5

Creating job 6

Creating job 7

Creating job 8

Creating job 9

Létrehozás tartott: 0.1460084 mp

Futtatás tartott (-id 8680): 0.4150237 mp

Látható, hogy jóval gyorsabb lett mind a job-ok elkészítése és a futtatásuk. Ráadásul a kapott eredmény natív processz objektum, nem pedig egy szerializáláson átesett módosított objektum:

PS C:\> $output[0][0].pstypenames[0]

System.Diagnostics.Process

És nézzük az összes processzel:

Creating job 0

Creating job 1

Creating job 2

Creating job 3

Creating job 4

Creating job 5

Creating job 6

Creating job 7

Creating job 8

Creating job 9

Létrehozás tartott: 0.7194031 mp

Futtatás tartott (): 1.9968035 mp

Itt még nagyobb a nyereség, hiszen a nagyobb kimenet hatékonyabb átadásán többet spóroltunk.



Word To HTML Converter