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.