Тестирование производительности двумя методами целочисленного деления PowerShell - PullRequest
1 голос
/ 15 января 2012

Microsoft technet предлагает [Math]::Floor([int]$a / [int]$b) для целочисленного деления .Я считаю, что [int][Math]::Floor($a / $b) является более читабельным и более производительным благодаря одной операции преобразования. Я доказал, что оба метода эквивалентны. Однако я не могу получить согласованные результаты.Моя методология предполагает повторение обеих методологий 10000 раз и измерение результатов с помощью командлета Measure-Command .Однако не может составить тест, в котором один тест выполняется несколько раз лучше, чем другой.Мой код приведен ниже:

Write-Host
$loopLength = 10000

$runtime = Measure-Command {
    1..$loopLength | ForEach-Object {
        Foreach ($divisor in 2,3,5,7) {
            [Math]::Floor([int]$_ / [int]$divisor) > $null
        }
    }
}

"Double Cast: $($runtime.TotalMilliSeconds)"

$runtime = Measure-Command {
    1..$loopLength | ForEach-Object {
        Foreach ($divisor in 2,3,5,7) {
            [int][Math]::Floor($_ / $divisor) > $null           
        }
    }
}
"Single Cast: $($runtime.TotalMilliSeconds)"

Как изменить код, чтобы получить согласованные результаты, доказывающие, что один метод лучше другого.

Ответы [ 2 ]

1 голос
/ 16 января 2012

Как по мне, такая оптимизация производительности не очень важна.Сам PowerShell намного медленнее, чем скомпилированные языки, поэтому, если вам действительно нужна производительность, используйте скомпилированные языки или скомпилируйте свой код с Add-Type.

Кроме того - если вы тестируете производительность, вам нужен минимальный другой код, который мог быизменить результаты.Foreach-Object сама добавляет свою сложность.Вот почему я бы посоветовал вместо этого использовать оператор foreach.

Удивительно, но результаты на моей машине иногда противоположны ..

[76]: $loopLength = 100000
[77]:
[77]: $runtime = Measure-Command {
>>     foreach($i in 1..$loopLength) {
>>         Foreach ($divisor in 2,3,5,7) {
>>             [Math]::Floor([int]$i / [int]$divisor) > $null
>>         }
>>     }
>> }
>>
[78]: "Double Cast: $($runtime.TotalMilliSeconds)"
Double Cast: 16294.3328
[79]:
[79]: $runtime = Measure-Command {
>>     foreach($i in 1..$loopLength) {
>>         Foreach ($divisor in 2,3,5,7) {
>>             [int][Math]::Floor($i / $divisor) > $null
>>         }
>>     }
>> }
>> "Single Cast: $($runtime.TotalMilliSeconds)"
>>
Single Cast: 15924.3836
0 голосов
/ 15 января 2012

Пример на TechNet довольно глупый, потому что числа уже имеют тип System.Int32.Взгляните на этот пример:

PS C:\Users\andy> [math]::floor( 100 / 26 ).GetType().Fullname
System.Double
PS C:\Users\andy> (100).GetType().FullName
System.Int32
PS C:\Users\andy> [int].FullName
System.Int32

Так что совершенно необязательно ставить [int] перед параметрами метода Floor, потому что они уже имеют тип System.Int32.

Кроме того,в любом случае вы не захотите приводить возвращенное System.Double к Int32, потому что возвращаемое значение может быть больше, чем может содержать Int32.Например:

PS C:\Users\andy> [int][math]::floor( ([int]::MaxValue + 1) / 1 )
Cannot convert value "2147483648" to type "System.Int32". Error: "Value was either too large or too small for an Int32."

Что касается производительности, разница в скорости незначительна.Движок PowerShell выполняет множество типов адаптации и приведения за кулисы вне зависимости от того, хотите вы этого или нет ... Он был спроектирован таким образом, чтобы системным администраторам не приходилось слишком сильно беспокоиться о типах int, double, decimals и т. Д. ...Число это число верно?;-) Например:

[Math]::Floor("123")
# This outputs 123 as System.Double.

Это даже не скомпилируется в C #.Среда выполнения PowerShell выполняет необходимое приведение в соответствие с сигнатурой метода Floor.

Другой пример:

"2" / "1"
# This outputs 2 as System.Int32.

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

Вотрезультаты производительности с моей машины:

function Get-SingleCastTime {
    $runtime = Measure-Command {
        1..10000 | ForEach-Object {
            Foreach ($divisor in 2,3,5,7) {
                [int][Math]::Floor($_ / $divisor) > $null          
            }
        }
    }
    "Single Cast: $($runtime.TotalMilliSeconds)"
}

function Get-DoubleCastTime {
    $runtime = Measure-Command {
        1..10000 | ForEach-Object {
            Foreach ($divisor in 2,3,5,7) {
                [Math]::Floor([int]$_ / [int]$divisor) > $null
            }
        }
    }

    "Double Cast: $($runtime.TotalMilliSeconds)"
}

Get-SingleCastTime
#Single Cast: 614.6537

Get-DoubleCastTime
#Double Cast: 545.2668

Get-DoubleCastTime
#Double Cast: 514.2103

Get-SingleCastTime
#Single Cast: 526.9188
...