Не так давно я публиковал скрипт для расшифровки опции 82 из DHCP лога Windows Server 2012/R2. Эта заготовка требовала обертки для полноценного использования на практике. Такой скрипт был написан, и в процессе его отладки и оптимизации выяснились некоторые интересные факты о производительности Powershell.
Лог файл DHCP в лога Windows Server 2012/R2 имеет оригинальный формат: в начале идет текст с описанием опций и только потом основная часть лога почти в формате CSV. (Почему «почти» — об этом в другой раз.)
Поэтому для считывания файла журнала первоначально была использована конструкция, которая пропускала первые 33 описательные строки:
$content = Get-Content $logfileName | Select-Object -Skip 33 | # Convert from CSV to PSObject ConvertFrom-Csv -Header $Header | # Filter only "Renew" rows and "Assign" rows ? {$_.Id -eq "11" -or $_.Id -eq "10"} | % { $_.sortDateTime = ([datetime]"$($_.Date) $($_.Time)").ToString("yyyyMMddHHmmss"); $_ } | % { if ( $_.sortDateTime -gt $script:UnuqueRows[$_.'MAC Address'].sortDateTime ) { … } }
Эта конструкция в моём примере выполнялась за 22 секунды для всего набора журналов (14 штук).
Только на само считывание
$content = Get-Content $logfileName | Select-Object -Skip 33 |
затрачивалось 8 секунд! Учитывая очень скромный размер журналов, участвующих в тесте, это было явно расточительно.
Тут появилась идея попробовать командлет Select-String, чтобы убить сразу трёх зайцев: во-первых, избавиться от явно медленной конструкции Select -Skip 33, во-вторых, сразу отфильтровать только нужные строки (ID=10 и ID=11) и как следствие этого избавиться от лишних вызовов ConvertFrom-Csv и в-третьих, всё вместе уменьшало длину конвейера на три шага.
В результате только считывание:
$content = Select-String -Path $logfileName -Pattern "^(10|11)," |
стало занимать 2 секунды вместо 8 – в четыре раза увеличилось быстродействие!
Вся конструкция стала выглядеть так:
$content = Select-String -Path $logfileName -Pattern "^(10|11)," | Select -ExpandProperty Line | # Convert from CSV to PSObject ConvertFrom-Csv -Header $Header | % { $_.sortDateTime = ([datetime]"$($_.Date) $($_.Time)").ToString("yyyyMMddHHmmss"); $_ } | % { if ( $_.sortDateTime -gt $script:UnuqueRows[$_.'MAC Address'].sortDateTime ) { … } }
Оказалось, что последние для шага конвейера можно заменить одним. Финальный вариант:
$content = Select-String -Path $logfileName -Pattern "^(10|11)," | Select -ExpandProperty Line | # Convert from CSV to PSObject ConvertFrom-Csv -Header $Header | % { $_.sortDateTime = ([datetime]"$($_.Date) $($_.Time)").ToString("yyyyMMddHHmmss") if ( $_.sortDateTime -gt $script:UnuqueRows[$_.'MAC Address'].sortDateTime ) { … } }
показал прекрасное быстродействие: 7 секунд вместо первоначальных 22-х – почти в три раза возросла производительность скрипта даже без оптимизации основной функции расшифровки DHCP опции 82!
Эффект оптимизации будет ещё более ощутим на DHCP журналах большого размера.
Filed under: Powershell |
[…] Powershell – превратности производительности […]
[…] скрипта Powershell. Даже небольшие изменения в скрипте (см. Powershell – превратности производительности) способны уменьшить время выполнения скрипа в […]
Замена ^(10|11), на ^1[01], должна дать еще процентов 10
Замерил оба варианта — разницы не получилось, к сожалению :-( хотя хотелось.