Univerzális párhuzamosító függvény

Az előzőekből kiindulva készítsünk egy olyan függvényt, ami egy univerzális, párhuzamosan végrehajtó ForeEach‑Object, legyen a neve Invoke-MultiThread:

function Invoke-MultiThread {

param(

     [Parameter()]$script,

    [Parameter(ValueFromPipeline=$true)]$argument,

     [Parameter()]$maxthread = 5   

)

 

begin {

     $rp = [runspacefactory]::CreateRunspacePool(1, $maxthread)

     $rp.Open()

     $jobs = New-Object System.Collections.ArrayList

     $start = get-date

    $psb = $PSBoundParameters

 

     function Get-Results {

          param([switch]$wait)

          do {

                $ActiveThreads = 0

                $wasoutput = $false

                $hasdata = $false

                foreach($job in $jobs) {

                      if ($job.job.isCompleted) {

                            $job.thread.EndInvoke($job.job)

                            $wasoutput = $true

                            $job.thread.dispose()

                            $job.job = $null

                            $job.thread = $null

                      }

                      elseif ($job.job -ne $null) {

                            $ActiveThreads++

                            $hasdata = $true

                      }

                }

                if($psb.ContainsKey("Verbose") -and $psb.verbose -and $wait -and $wasoutput){

                      $elapsed = "{0:n2}" -f ((get-date) - $start).totalseconds

                      Write-host "$elapsed sec - Active threads: $activethreads" -ForegroundColor green

                }

                if ($hasdata -and $wait) {

                      Start-Sleep -Milliseconds 500

                }

          } while ($hasdata -and $wait)

     }

}

process{

     $p = [powershell]::Create().AddScript($Script).AddArgument($argument)

     $p.RunspacePool = $rp

     $rv = New-Object -TypeName PSObject -Property @{

                Thread = $p

                 Job = $p.BeginInvoke()

          }

     [void]$jobs.Add($rv)

     Get-Results

}

end{

     Get-Results -wait

     $rp.Close()

}

}

Nagyjából megtisztítottam minden sallangtól a belsejét, egy kicsit átalakított –verbose üzemmódot hagytam csak benne. A futtatandó szkritblokk:

$ScriptBlock = {

            param($adat)

            "Adat: $adat"

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

                Start-Sleep 1

                "i: $i"

            }

        }

Nézzük, hogyan fut 2 szállal:

PS C:\> 1..5 | Invoke-MultiThread -script $ScriptBlock -maxthread 2 -verbose

Adat: 1

i: 0

1,01 sec - Active threads: 4

Adat: 2

i: 0

i: 1

2,07 sec - Active threads: 3

Adat: 3

i: 0

i: 1

i: 2

4,09 sec - Active threads: 2

Adat: 4

i: 0

i: 1

i: 2

i: 3

6,13 sec - Active threads: 1

Adat: 5

i: 0

i: 1

i: 2

i: 3

i: 4

9,15 sec - Active threads: 0

A 2 párhuzamos szálnál 5 elem iterálásához kicsit több mint 9 mp-re volt szükség. Az 1 mp-es és 2 mp-es szálat indította egyszerre, majd az 1-es befejezésekor indította a 3-ast, stb., valahogy így:

ábra 145 . 5 feladat 2 szálban futtatása

Nézzük, mi van, ha növeljük a párhuzamos szálak számát:

PS C:\> 1..5 | Invoke-MultiThread -script $ScriptBlock -maxthread 5 -verbose

Adat: 1

i: 0

1,03 sec - Active threads: 4

Adat: 2

i: 0

i: 1

2,09 sec - Active threads: 3

Adat: 3

i: 0

i: 1

i: 2

3,11 sec - Active threads: 2

Adat: 4

i: 0

i: 1

i: 2

i: 3

4,13 sec - Active threads: 1

Adat: 5

i: 0

i: 1

i: 2

i: 3

i: 4

5,15 sec - Active threads: 0

Láthatóan egyszerre elvégzett minden feladatot, a teljes futtatáshoz kicsit több mint 5 mp-re volt szükség, azaz a leghosszabb feladat határozta meg a futási időt.

Tovább is lehetne ezt még fejleszteni, hogy a szálak számának beállításához vegye figyelembe a mindenkori processzor és memória igénybevételt, és a szálak számát úgy hangolja, hogy a gép ne terhelje halálra magát.



Word To HTML Converter