首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >巨大的性能差异: PowerShell核心与5.1

巨大的性能差异: PowerShell核心与5.1
EN

Code Review用户
提问于 2019-05-26 21:00:00
回答 1查看 555关注 0票数 -1

最近我回答了关于性能的另一个问题。利用PowerShell成功地找到了一种解决方案,并利用PowerShell内核验证了该方案的良好速度.

但是,在PowerShell 5.1中运行相同的脚本(S)会显示出完全不同的结果,而absolutely在性能改进方面更糟糕。此外,原始脚本运行速度超过4×慢于ISE。

因此,我的问题是:<#>where为如此巨大的差异提供了一个理由,在PowerShell脚本中我应该避免什么(或者相反,可能显式地加载.NET库或类似的东西)?

PowerShell-ISE:性能改进cca 10:1 ():

代码语言:javascript
复制
.\cr\122635wrapper.ps1 -maxLoop 8;$Host.Name;$PSVersionTable

maxRange=7,lowCountThreshold=1,operators=“+-*/ permutations=4096 formatString=1{0}2{1}3{2}4{3}6{5}7”。7 269 756 19 574412详细: maxRange=7,lowCountThreshold=1,Operators=“+-*/ permutations=4096 formatString=”1{5}2{4}3{2}4{1}6{0}7“回答7284 839 1,911312 Windows PowerShell ISE主机名值.503 PSEdition桌面PSCompatibleVersions {1.0,BuildVersion 10.0.17763.503 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1

PowerShell核心:性能改进28:1 (优秀):

代码语言:javascript
复制
pwsh -noprofile -command .\cr\122635wrapper.ps1 -maxLoop 8;$Host.Name;$PSVersionTable

maxRange=7,lowCountThreshold=1,operators=“+-*/ permutations=4096 formatString=1{0}2{1}3{2}4{3}6{5}7”。7 269 756 22 0310531详细: maxRange=7,lowCountThreshold=1,Operators=“+-*/ permutations=4096 formatString=”1{5}2{4}3{2}4{1}6{0}7“回答7 284 839 0 7800336 ConsoleHost名称值6.2.0OS MicrosoftWindows10.0.17763平台Win32NT PSCompatibleVersions {1.0,2.0,3.0,4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0

PowerShell 5.1:性能改进cca 4:3 (very可怜):

代码语言:javascript
复制
powershell -noprofile -command .\cr\122635wrapper.ps1 -maxLoop 8;$Host.Name;$PSVersionTable

maxRange=7,lowCountThreshold=1,operators=“+-*/ permutations=4096 formatString=1{0}2{1}3{2}4{3}6{5}7”。7 269 756 87,1714765详细: maxRange=7,lowCountThreshold=1,operators="+-*/“permutations=4096 formatString=”1{5}2{4}3{3}4{2}6{0}7“答案为7 284 839 64,888286 ConsoleHost名称值- PSVersion 5.1.17763.503 PSEdition Desktop PSCompatibleVersions {1.0,BuildVersion 10.0.17763.503 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1

编辑

包括代码片段从链接到关于性能的另一个问题

122635responer.ps1脚本:

代码语言:javascript
复制
# [CmdletBinding(PositionalBinding=$false)] # slows script execution cca 50%
param (     # Variables
    [parameter()]                  # [ValidateRange(3,20)] # ???
    [int]$maxRange = 9,
    [parameter()]
    [int]$lowCountThreshold = 5,
    [parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$opString = '+-*/'     # Mathematical Operators as string
)
Begin {
    Set-StrictMode -Version Latest
    # cast $operators variable as an array of characters
    $operators = [char[]]$opString
    $opsCount  = $operators.Count
    # Define the number range for calculations. 13 would make for the largest values 13!. Cap the script as 13
    $maxRangeMinus1 = $maxRange - 1
    # Build an array for extending 
    $maxOpsArray = 1..$maxRange
    for ( $i=0; $i -lt $maxRange; $i++ ) {
        $maxOpsArray[$maxRangeMinus1 -$i] = ,$operators[0] * $i
    }
    # Build the format string that will be used for invoking.
    # Will look like 1{2}2{1}3{0}4. Acting as place holders for mathematic operators
    [string]$formatString = -join (1..($maxRangeMinus1) | 
        ForEach-Object{"$_{$([int]$maxRangeMinus1 - $_)}"}) + $maxRange # reverse order
      # ForEach-Object{"$_{$([int]$_ - 1)}"}) + $maxRange  # $range[-1] # ascending order
      # ascending order would require `[array]::Reverse($newOperatorArr)` below in the process loop
    if ( $maxRange -gt 11 ) {
        # force decimal computing in following `$DataTable.Compute( $mathString, '')`
        $formatString = $formatString.Replace('{','.0{') + '.0'
    }
    # Determine the number of possible permutations of those operators inbetween the number set. 
    [int64]$permutations = [System.Math]::Pow($opsCount, $maxRangeMinus1)
    # Narrow down $alphanumerics array size to necessary count
    $alphanumerics = $([char[]]'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                      )[0..($opsCount -1)]
    Write-Verbose -Verbose -Message `
      ("maxRange=$maxRange, lowCountThreshold=$lowCountThreshold, operators=""$(-join $operators)""" `
     + "`r`npermutations=$permutations formatString=""$formatString""")
    $DataTable=[System.Data.DataTable]::new()
    $Error.Clear()                             # for debugging purposes
}
Process {
# Cycle each permutation. Use `for` loop instead of `0..($permutations - 1) | ForEach-Object`
$( for ( $i=0; $i -lt $permutations; $i++ ) {
    # Build an array of operators:
    #        ( based on the number converted to base `$opsCount` )
        $Number = $i
        $newOperatorArr = @( $( do {
            $Remainder = $Number % $opsCount
            # Get the associated character
            $operators[$Remainder]
            $Number = ($Number - $Remainder) / $opsCount
        } while ($Number -gt 0) ))
        # Extend array of operators to appropriate length if necessary
        if ( $newOperatorArr.Count -lt $maxRangeMinus1 ) {
            $newOperatorArr += $maxOpsArray[$newOperatorArr.Count]
        }
    ### [array]::Reverse($newOperatorArr) # only if `$formatString` is in ascending order
    $mathString = $formatString -f @( $newOperatorArr )
    # evaluate math expression using the Compute method of the DataTable class
    #                          rather than time consuming Invoke-Expression
    $value122635 = $DataTable.Compute( $mathString, '')
    # Effectively reduce the output size in advance: refuse "non-integers"
    if ( $value122635 -eq [System.Math]::Floor($value122635) ) {
        # Build an object that contains the result and the mathematical expression 
        [pscustomobject]@{
            Expression = $mathString
            Value      = [System.Math]::Floor($value122635) # [int64]$value122635
        }
    }
    # Since this take a while try and give the user some semblance of progress.
    Write-Progress -Activity "Performing mathematical calculations" `
        -Status "Please wait." -PercentComplete (100 * $i / $permutations) `
        -CurrentOperation "$([math]::Round(100 * $i / $permutations))% Completed."
    # Only give group results
} ) | Group-Object Value |
      Where-Object{$_.Count -ge $lowCountThreshold} |
       Sort-Object -property Count <# -Descending <##>, @{Expression = {[int]$_.Name} }

122635wrapper.ps1 脚本

代码语言:javascript
复制
param (
    [parameter()]                  
    [ValidateRange(8,13)]
    [int]$maxLoop = 12
)

$y = (Measure-Command {$x = D:\PShell\CR\122635.ps1}).TotalSeconds
$z = ($x | Measure-Object -Property  Count -Sum).Sum
'orig.  {0,4} {1,9} {2,9} {3,16}' -f 7, $x.count, $z, $y

for ( $icnt=7; $icnt -lt $maxLoop; $icnt++ ) { 
    $y = (Measure-Command {
        $x = D:\PShell\CR\122635answer.ps1 -maxRange $icnt -lowCountThreshold 1
                          }).TotalSeconds
    $z = ($x | Measure-Object -Property  Count -Sum).Sum
    'answer {0,4} {1,9} {2,9} {3,16}' -f $icnt, $x.count, $z, $y
    if ($icnt -eq 7) {''}
}

The原始 122635.ps1脚本:

代码语言:javascript
复制
function ConvertTo-Base
{
    [CmdletBinding()]
    param (
        [parameter(ValueFromPipeline=$true,Mandatory=$True, HelpMessage="Base10 Integer number to convert to another base")]
        [int]$Number=1000,
        [parameter(Mandatory=$True)]
        [ValidateRange(2,20)]
        [int]$Base
    )
    [char[]]$alphanumerics = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    do
    {
        # Determine the remainder
        $Remainder = ($Number % $Base)
        # Get the associated character and add it to the beginning of the string.
        $newBaseValue = "$($alphanumerics[$Remainder])$newBaseValue"
        # Adjust the number to remove the calculated portion
        $Number = ($Number - $Remainder) / $Base
        # Loop until we have processed the whole number
    } while ($Number -gt 0)

    return $newBaseValue
}

# Variables
$maxRange = 3                  #13 would make for the largest values 13!. Cap the script as 13
$lowCountThreshold = 1         # Only show group results where the match exists more than five times. 

# Mathematical Operators 
[char[]]$operators = "+-*/"

# Define the number range for calculations. 13 would make for the largest values 13!. Cap the script as 13
$range = 1..$maxRange

# Build the format string that will be used for invoking. Will look like 1{0}2{1}3. Acting as place holders for mathematic operators
$formatString = -join (1..($range.count - 1) | ForEach-Object{"$_{$([int]$_ - 1)}"}) + $range[-1]

# Determine the number of possible permutations of those operators inbetween the number set. 
$permutations = [System.Math]::Pow($operators.Count,$range.count - 1)

# Cycle each permutation
0..($permutations - 1) | ForEach-Object{
    # Convert the number to a base equal to the element count in operators. Use those values to represent the index of the operators array.
    $mathString = $formatString  -f @([string[]][char[]]((ConvertTo-Base -Number $_ -Base $operators.Count).PadLeft($range.count - 1,"0")) | ForEach-Object{$operators[[int]$_]})
    # Build an object that contains the result and the mathematical expression 
    [pscustomobject]@{
        Expression = $mathString
        Value = Invoke-Expression $mathString      
    }
    # Since this take a while try and give the user some semblance of progress. 
    Write-Progress -Activity "Performing mathematical calculations" -Status "Please wait." -PercentComplete ($_ / $permutations * 100) -CurrentOperation "$([math]::Round($_ / $permutations * 100))% Completed."

    # Filter for whole number and only give group results
} | Where-Object{$_.Value -is [int32]} | Group-Object Value | Where-Object{$_.Count -ge $lowCountThreshold} | Sort-Object Count -Descending
EN

回答 1

Code Review用户

回答已采纳

发布于 2019-05-27 07:52:19

通常,为了找出代码的哪一部分是慢的,您可以在分析器中运行它。然而,不幸的是,PowerShell没有分析器,所以我们必须使用其他方法。找到慢的部分有多种方法。

您可以在您的代码中放置计时代码,以度量各个部件所需的时间。.NET 秒表类在这里可能会有所帮助。

另一种简单的方法就是简单地将代码中的一些切碎,直到它加速。我就是这么用你的密码的。

我尝试的第一件事是对Write-Progress进行评论。这似乎是一个可能的候选人,因为在ISE和控制台是不同的。当我这么做的时候,代码立刻加速了。看来这就是罪魁祸首。

你要做的就是少打电话。你可以这样做:

代码语言:javascript
复制
# Show progress bar. We don't call Write-Progress each time through the loop 
# because that is slow.
if ($i % 1000 -eq 0)
{
    Write-Progress -Activity "Performing mathematical calculations" `
        -Status "Please wait." -PercentComplete (100 * $i / $permutations) `
        -CurrentOperation "$([math]::Round(100 * $i / $permutations))% Completed."
}
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/221082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档