| Dneska mě napadlo trošku porovnat rychlosti dvou programátorských přístupů v jazyce PowerShell. PowerShell umožňuje ve skriptech používat pajpu (pipe) a její příkazy jako je ForEach-Object, nebo Where-Object, což je někdy úžasně jednoduché. Nebo na to můžete jít spíše programátorskou syntaxí a udělat to stejné pomocí foreach a if klíčových slov.
Je v tom nějaký rozdíl? Tak rozdíly jsou například v nemožnosti použít klíčové slovo break uvnitř pajpy (teda můžete, ale dělá to věci :-)). Nebo Where-Object je málo flexibilní a těžko se dá udělat složitější else, nebo elseif logika uvnitř tohoto cmdletu. Podobně $MyInvocation.MyCommand je prázdný, pokud se použije uvnitř pajpy (pipe).
Ale o to mi tu nešlo. Chtěl jsem porovnat rychlosti. Tak jsem si napsal následující skriptík. V první části se jenom generuje pole hodnot. To trvá hodně dlouho a obě metody jsou poměrně srovnatelné. To je tím, že většina času, se spotřebuje na plnění toho pole. Použil jsem ArrayList, protože kdybych to přidával do pole, tak by to bylo dokonce nelineárně strašlivě zdlouhavé - pole se kopíruje při přidávání prvku. Ale i zde je vidět, že cmdlet ForEach-Object je pomalejší.
Podstatně drsnější porovnání ovšem nastane v druhé části, kde se to pole už jenom projíždí. Tam je kombinace foreach a if dokonce cca 10x rychlejší, než cmdlet ForEach-Object a Where-Object.
$bigArrayCount = 200000
[System.Collections.ArrayList] $bigArray = @()
$idArray = (1..$bigArrayCount)
$bigArray = @()
$start = Get-Date
$idArray | % { $bigArray.Add($_) | Out-Null }
$end = Get-Date
Write-Host ('Filling a big array with ForEach-Object: {0:N1} sec.' -f ($end - $start).TotalSeconds) -For Green
$bigArray = @()
$start = Get-Date
foreach ($id in $idArray) { $bigArray.Add($_) | Out-Null }
$end = Get-Date
Write-Host ('Filling a big array with foreach keyword: {0:N1} sec.' -f ($end - $start).TotalSeconds) -For Green
$start = Get-Date
$bigArray | ? { $_ -gt ($bigArrayCount / 4) } | % { $oneCalc = 3 * $_ - 80 }
$end = Get-Date
Write-Host ('Going through the big array with Where-Object and ForEach-Object: {0:N1} sec.' -f ($end - $start).TotalSeconds) -For Green
$start = Get-Date
foreach ($one in $bigArray) { if ($one -gt ($bigArrayCount / 4)) { $oneCalc = 3 * $_ - 80 } }
$end = Get-Date
Write-Host ('Going through the big array with foreach and if keywords: {0:N1} sec.' -f ($end - $start).TotalSeconds) -For Green
Závěr
Pajpování je paráda, ale pro větší kódy se to moc nehodí. Nehledě na to, že uvnitř nejde použít break, což je pro mě osobně dost podstatné.
Poznámka
Mimochodem, výsledné hodnoty na mém noťasu HP 6730b s procesorem Intel Core 2 Duo CPU @2.26 GHz s pamětí o rychlosti 800 jsou:
Filling a big array with ForEach-Object: 22,3 sec.
Filling a big array with foreach keyword: 14,3 sec.
Going through the big array with Where-Object and ForEach-Object: 9,7 sec.
Going through the big array with foreach and if keywords: 0,6 sec.
Tak kdyby to někdo třeba vyzkoušel, speciálně by mě osobně zajímal nějaký Lenovo T430, tak to bych byl rád :-) Pokud chcete vědět, jak rychlou máte RAM a CPUčka, zjistíte to takto:
gwmi win32_physicalmemory | ft Capacity, Speed
gwmi win32_processor | ft Name, NumberOfCores, NumberOfLogicalProcessors
|