Статья размещена автором Бетке Сергей Сергеевич

Повышение производительности сценариев, или select-object + invoke-expression

С целью обработки журналов SMTP сервера приходится анализировать записи журнала, для чего решил загрузить весь журнал в конвейер. И наткнулся на крайне низкую производительность add-member. Но решений, как всегда, много. Найдём лучшее.

Итак речь пойдёт о модуле LogParser. Исходный код, который не блещет производительностью:

function Get-LPRecord {
    param (
        $LPRecordSet
    )

 	$LPRecord = new-Object System.Management.Automation.PSObject;
	if (-not $LPRecordSet.atEnd()) {
		$Record = $LPRecordSet.getRecord();
		for ([int]$i = 0; $i -lt $LPRecordSet.getColumnCount(); $i++) {        
			$LPRecord | add-member `
                -memberType NoteProperty `
                -name $LPRecordSet.getColumnName($i) `
                -value $Record.getValue($i)
		}
	}
	return $LPRecord;
}
 
function Get-LPRecordSet {
    param (
        [string]$query
    )

    $LPRecordSet = Invoke-LPExecute $query;

    LPRecords = new-object System.Management.Automation.PSObject[] 0;
    for(; -not $LPRecordSet.atEnd(); $LPRecordSet.moveNext()) {
    		$LPRecords += Get-LPRecord($LPRecordSet);
   	};
	$LPRecordSet.Close();
	return $LPRecords;
}

Естественно, код модуля подправлен для краткости. Полный вариант предлагаю посмотреть здесь.

Попробуем уйти от командлеты add-member. Предлагаю следующее решение:

function Get-LPRecordSet {
    param (
        [string]$query,
    )

   $LPRecordSet = Invoke-LPExecute $query;

	if (-not $LPRecordSet.atEnd()) {
		$exp = "select-object -property ```n" + (@( `
            for ([int]$i = 0; $i -lt $LPRecordSet.getColumnCount(); $i++) {
                "`t@{name=`"$($LPRecordSet.getColumnName($i))`";expression={`$_.getValue($i);};}";
            } `
        ) -join ", ```n");

    	$LPRecords = @( for(; -not $LPRecordSet.atEnd(); $LPRecordSet.moveNext()) {
            invoke-expression "`$LPRecordSet.getRecord() | $exp";
    	});
    };
	$LPRecordSet.Close();
	return $LPRecords;
}

Как видно, сначала мы формируем выражение powershell  в строке $exp, а затем формируем массив записей журнала, используя цикл for для перебора записей в полученном recordSet и invoke-expression для выполнения сформированного нами выражения, построенного на базе select-object. Производительность такого решения выше в разы по сравнению с первоначальным.

P.S. Рекомендую изучить статьи по данному вопросу:

Опубликовать комментарий

XHTML: Вы можете использовать следующие HTML теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Tags Связь с комментариями статьи:
RSS комментарии
Обратная ссылка