2015-03-05 2 views
3

Я использую PowerShell как можно больше для выполнения быстрых и простых задач сценариев; Много раз во время моей работы я буду использовать его для анализа данных, просеивания файла журнала или для создания файлов CSV \ Text.Эффективность сценария PowerShell

Я не могу понять, почему это может быть очень неэффективно для выполнения определенных задач \ IO данных. Я полагаю, что это связано с чем-то под капотом с тем, как он обрабатывает трубопроводы или что-то, чего я еще не понял.

Если взять следующую логику для генерации ABC123 идентификаторами, скомпилировать его в PowerShell и выполнить его, это займет менее 1 минуты до завершения:

$source = @' 
    public static System.Collections.Generic.List<String> GetIds() 
    { 
     System.Collections.Generic.List<String> retValue = new System.Collections.Generic.List<String>(); 
     for (int left = 97; left < 123; left++) 
     { 
      for (int middle = 97; middle < 123; middle++) 
      { 
       for (int right = 97; right < 123; right++) 
       { 
        for (int i = 1; i < 1000; i++) 
        { 
         String tmp = String.Format("{0}{1}{2}000", (char)left, (char)middle, (char)right); 
         retValue.Add(String.Format("{0}{1}", tmp.Substring(0, tmp.Length - i.ToString().Length), i)); 
        } 
       } 
      } 
     } 
     return retValue; 
    } 
'@ 
$util = Add-Type -Name "Utils" -MemberDefinition $source -PassThru -Language CSharp 

$start = get-date 
$ret = $util::GetIds() 
Write-Host ("Time: {0} minutes" -f ((get-date)-$start).TotalMinutes) 

Теперь возьмите ту же логику, запустить его через PowerShell без компиляции в сборе, и это занимает часов, чтобы закончить

$start = Get-Date 
$retValue = @() 
for ($left = 97; $left -lt 123; $left++) 
{ 
    for ($middle = 97; $middle -lt 123; $middle++) 
    { 
     for ($right = 97; $right -lt 123; $right++) 
     { 
      for ($i = 1; $i -lt 1000; $i++) 
      { 
       $tmp = ("{0}{1}{2}000" -f [char]$left, [char]$middle, [char]$right) 
       $retValue += ("{0}{1}" -f $tmp.Substring(0, $tmp.Length - $i.ToString().Length), $i) 
      } 
     } 
    } 
} 
Write-Host ("Time: {0} minutes" -f ((get-date)-$start).TotalMinutes) 

Почему это? Есть ли какой-то чрезмерный тип литья или неэффективная работа, которую я использую, что замедляет производительность?

ответ

4

Вы губите производительность здесь:

$retValue += ("{0}{1}" -f $tmp.Substring(0, $tmp.Length - $i.ToString().Length), $i) 

Массив дополнения очень «дорого» операция. То, что вы делаете, в основном создает новый массив каждый раз, состоящий из исходного массива плюс новый элемент.

Редактировать: Этот массив массивов не только неэффективен, но и абсолютно не нужен. Все, что вам нужно сделать, это просто передать эти значения в конвейер и присвоить результат обратно переменной.

$start = Get-Date 
$retValue = 
for ($left = 97; $left -lt 123; $left++) 
{ 
    for ($middle = 97; $middle -lt 123; $middle++) 
    { 
     for ($right = 97; $right -lt 123; $right++) 
     { 
      for ($i = 1; $i -lt 1000; $i++) 
      { 
       $tmp = ("{0}{1}{2}000" -f [char]$left, [char]$middle, [char]$right) 
       "{0}{1}" -f $tmp.Substring(0, $tmp.Length - $i.ToString().Length), $i 
      } 
     } 
    } 
} 
Write-Host ("Time: {0} minutes" -f ((get-date)-$start).TotalMinutes) 
Time: 1.866812045 minutes 
+0

очень приятно! Сейчас имеет большой смысл. Я принимаю 'System.Collections.Generic.List ' не тот же тип, что и '@()'. Does System.Collections.Generic.List .Add метод выполняет расширение массива? Еще раз спасибо! –

+0

Метод .add() общих списков намного эффективнее, чем добавление массива. Тип arralist кажется самым быстрым с точки зрения эффективного добавления элементов, но обычно вам нужно только сделать это в ситуациях, когда конвейер уже используется для других объектов, и вам нужно делать случайное накопление вне конвейера. – mjolinor

Смежные вопросы