none
Медленная работа фукнкции RRS feed

  • Вопрос

  • Всем привет.

    У меня есть функция, и хотелось бы понять, почему любимый язык так себя ведет. Одна функция выполняется быстро, вторая в несколько раз медленнее, создавая впечатление, что результат копируется в массив, а затем выдается из него вместе с опять же копированием куда-то в промежуточную область результатов. Могут уважаемые доны пояснить, почему

    (и что) так происходит. Замеры выполняются на WS 2012R2, Powershell 4.0

    Код:


    ####################################################################################################
    Function ModifyArrayByValue
    {
    	Param(
    		$arrArray
    	)
    
    	[void] $arrArray.Add(1)
    }
    ####################################################################################################
    
    
    
    
    ####################################################################################################
    Function ModifyArrayByRef
    {
    	Param(
    		[ref] $arrArray
    	)
    
    	[void] $arrArray.Value.Add(1)
    }
    ####################################################################################################
    
    
    
    $arrArray = New-Object System.Collections.ArrayList
    $strProgressBarActivity = "Modifying array..."
    $iItemsAmount = 100000
    $iItemIndex = 1
    $iTempPercentsCompleted = -1
    for ($iCounter = 0; $iCounter -lt $iItemsAmount; $iCounter++)
    {
    	$iPercentsCompleted = [System.Math]::Truncate($iItemIndex / $iItemsAmount * 100)
    	if ($iTempPercentsCompleted -ne $iPercentsCompleted)
    	{
    		Write-Progress -Activity $strProgressBarActivity -Status ($iPercentsCompleted.ToString() + "% Completed") -PercentComplete $iPercentsCompleted
    		$iTempPercentsCompleted = $iPercentsCompleted
    	}
    	$iItemIndex++
    
    #	ModifyArrayByValue $arrArray
    #	ModifyArrayByRef ([ref] $arrArray)
    }





    • Изменено Satysfy_me 29 ноября 2015 г. 12:42
    29 ноября 2015 г. 12:32

Ответы

  • Запустить PowerShell_ISE для наглядности и посмотреть, что происходит на высоком уровне с помощью Trace-Command. Про нижний не скажу, т.к. у меня не хватит компетенции.

    $arrArray = New-Object System.Collections.ArrayList 100000
    for ($iCounter = 1; $iCounter -lt 100000; $iCounter++)
    {
    	[void] $arrArray.Add(1)
    }
    
    Trace-Command -Expression {ModifyArrayByValue $arrArray} -PSHost  -Name TypeConversion

    Обратить внимание на DEBUG: ParameterBinding Information: 0 : BIND arg [1 1 1 1 1 1 1 ...........

    И сколько ненужных операций с преобразованием :

    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.InvocationInfo" to "System.Management.Automation.InvocationInfo".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.InvocationInfo" to "System.Management.Automation.InvocationInfo".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.PSBoundParametersDictionary" to "System.Management.Automation.PSBoundParametersDictionary"
    .
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Collections.ArrayList+ArrayListEnumeratorSimple" to "System.Object".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type

    • Помечено в качестве ответа Satysfy_me 29 ноября 2015 г. 20:59
    29 ноября 2015 г. 19:33
    Отвечающий

Все ответы

  • Чем больше становиться массив который вы создаете, тем медленнее будет выполнятся код. Каждый раз когда вы добавляете новый элемент в массив он уничтожается и создается заново с новым количеством элементов.
    29 ноября 2015 г. 13:06
  • Самый медленный способ ModifyArrayByRef, затем ModifyArrayByValue. Использование [void] $arrArray.Add(1) в цикле for в разы выигрывает у этих функций, которые только тормозят работу и не дают выигрыша, а только добавляют избыточность.

    Measure-Command {
    	$arrArray = New-Object System.Collections.ArrayList
    	for ($iCounter = 1; $iCounter -lt 100000; $iCounter++)
    	{
    		ModifyArrayByRef ([ref] $arrArray)
    	}
    }
    
    Measure-Command {
    	$arrArray = New-Object System.Collections.ArrayList
    	for ($iCounter = 1; $iCounter -lt 100000; $iCounter++)
    	{
    		ModifyArrayByValue $arrArray
    	}
    }
    
    
    Measure-Command {
    	$arrArray = New-Object System.Collections.ArrayList
    	for ($iCounter = 1; $iCounter -lt 100000; $iCounter++)
    	{
    		[void] $arrArray.Add(1)
    	}
    }
    
    Days              : 0
    Hours             : 0
    Minutes           : 0
    Seconds           : 10
    Milliseconds      : 342
    Ticks             : 103422561
    TotalDays         : 0,000119702038194444
    TotalHours        : 0,00287284891666667
    TotalMinutes      : 0,172370935
    TotalSeconds      : 10,3422561
    TotalMilliseconds : 10342,2561
    
    Days              : 0
    Hours             : 0
    Minutes           : 0
    Seconds           : 6
    Milliseconds      : 595
    Ticks             : 65951362
    TotalDays         : 7,63325949074074E-05
    TotalHours        : 0,00183198227777778
    TotalMinutes      : 0,109918936666667
    TotalSeconds      : 6,5951362
    TotalMilliseconds : 6595,1362
    
    Days              : 0
    Hours             : 0
    Minutes           : 0
    Seconds           : 0
    Milliseconds      : 400
    Ticks             : 4003982
    TotalDays         : 4,63423842592593E-06
    TotalHours        : 0,000111221722222222
    TotalMinutes      : 0,00667330333333333
    TotalSeconds      : 0,4003982
    TotalMilliseconds : 400,3982
    
    

    Заодно, можно посмотреть, сколько операций происходит в функциях, которые тратят время и сколько в

    [void] $arrArray.Add(1) .

    $arrArray = New-Object System.Collections.ArrayList
    Trace-Command -Expression {[void]$arrArray.Add(1)} -PSHost  -Name *
    
    $arrArray = New-Object System.Collections.ArrayList
    Trace-Command -Expression {ModifyArrayByRef ([ref] $arrArray)} -PSHost  -Name *
    
    $arrArray = New-Object System.Collections.ArrayList
    Trace-Command -Expression {ModifyArrayByValue $arrArray} -PSHost  -Name *
    Byref,ByVal - передача параметров в C#

    Parameter passing in C#  - http://www.leerichardson.com/2007/01/parameter-passing-in-c.html
    Parameter passing in C# - http://www.yoda.arachsys.com/csharp/parameters.html#params

    В топике можно прочитать про сравнение в скорости:

    Which is faster? ByVal or ByRef? - http://stackoverflow.com/questions/408101/which-is-faster-byval-or-byref

    От гуру Jon Skeet:

    In practice, you should almost never worry about this. Write the most readable code possible, which almost always means passing parameters by value instead of reference. I use ByRef very rarely.

    If you want to improve performance and think that ByRef will help you, please benchmark it carefully (in your exact situation) before committing to it.

    29 ноября 2015 г. 16:18
    Отвечающий
  • Олег, складывается впечатление, что Вы сами не понимаете того, что говорите.
    29 ноября 2015 г. 18:21
  • Kazun, при всем моем уважении, попробуйте запустить код на Windows 7, и Вы увидите, что как раз наоборот, byref работает быстрее. на powershell 2.0 / 3.0 оно работает наоборот, поэтому и возник вопрос, скажем так философско- архитектурный.

    Безусловно, код сильно упрощен, этот пример взят с целью демонстрации. Можно просто запустить код без измерения- это видно наглядно.


    29 ноября 2015 г. 18:28
  • Запустил на Windows 7 ,да функция ModifyArrayByRef работает быстрее,чем ModifyArrayByValue. Разработчики оптимизировали код для работы с collections, возможно по этой причине - теперь обе функции в PsV4 работают быстрее.

    Хороший пример, как даже простой код можно усложнить, что он будет работать в разы медленнее и зависеть от версии PowerShell ,и "позволяет легко выстрелить себе в ногу".


    Ps. На Windows 10 PsV5 - ModifyArrayByRef работает быстрее,чем ModifyArrayByValue. Так что только тесты, тесты и тесты )
    • Изменено KazunEditor 29 ноября 2015 г. 19:20
    29 ноября 2015 г. 19:12
    Отвечающий
  • Безусловно это так, хотя ответа на свой вопрос- почему и что в действительности происходит я пока не получил.
    29 ноября 2015 г. 19:21
  • Запустить PowerShell_ISE для наглядности и посмотреть, что происходит на высоком уровне с помощью Trace-Command. Про нижний не скажу, т.к. у меня не хватит компетенции.

    $arrArray = New-Object System.Collections.ArrayList 100000
    for ($iCounter = 1; $iCounter -lt 100000; $iCounter++)
    {
    	[void] $arrArray.Add(1)
    }
    
    Trace-Command -Expression {ModifyArrayByValue $arrArray} -PSHost  -Name TypeConversion

    Обратить внимание на DEBUG: ParameterBinding Information: 0 : BIND arg [1 1 1 1 1 1 1 ...........

    И сколько ненужных операций с преобразованием :

    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.InvocationInfo" to "System.Management.Automation.InvocationInfo".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.InvocationInfo" to "System.Management.Automation.InvocationInfo".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "" to "System.String".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Management.Automation.PSBoundParametersDictionary" to "System.Management.Automation.PSBoundParametersDictionary"
    .
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
    DEBUG: TypeConversion Information: 0 : Converting "System.Collections.ArrayList+ArrayListEnumeratorSimple" to "System.Object".
    DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type

    • Помечено в качестве ответа Satysfy_me 29 ноября 2015 г. 20:59
    29 ноября 2015 г. 19:33
    Отвечающий