Cha*_*ynt 13 performance powershell
我编写了一个 PowerShell 模块,它从不同的源文件(即每个函数一个 .ps1 文件)中提取函数定义。这使我们(作为一个团队)可以并行处理不同的功能。模块(.psm1 文件)获取可用的 .ps1 文件列表...
$Functions = Get-ChildItem -Path $FunctionPath *.ps1
Run Code Online (Sandbox Code Playgroud)
...然后遍历列表并通过点源引入每个函数定义:
foreach($Function in $Functions) {
. $Function.Fullname # Can be slow
}
Run Code Online (Sandbox Code Playgroud)
问题:我们注意到,完成的速度可能会有很大差异,大约 50 个源文件的时间从 10 秒到 180 秒不等,这取决于我们测试的机器。我们无法解释所用时间的巨大差异,并且相信我们已经控制了诸如机器类型、操作系统、用户帐户、管理员权限、PS 配置文件、PS 版本等变量。在同一主机上,相同的主机所用的时间可能会有所不同。用户从一天到下一天。
我们确实想知道这是否是磁盘访问的问题,并测试了我们从磁盘读取数据的速度。事实证明,运行Get-Content所有这些文件的速度非常快,我们在解决问题的方法中利用了这一点:
foreach($Function in $Functions) {
Invoke-Expression (Get-Content $Function.Fullname -Raw) # Is quick
}
Run Code Online (Sandbox Code Playgroud)
为什么通过点源添加这些函数比读取和执行文件内容慢得多?
Ben*_*n N 17
首先,一些脚本来帮助我们测试这个。这会生成 2000 个脚本文件,每个文件都有一个小函数:
1..2000 | % { "Function Test$_(`$someArg) { Return `$someArg * $_ }" > "test$_.ps1" }
Run Code Online (Sandbox Code Playgroud)
这应该足以使正常的启动开销无关紧要。如果您愿意,可以添加更多。这使用点源加载它们:
dir test*.ps1 | % {. $_.FullName}
Run Code Online (Sandbox Code Playgroud)
这通过首先阅读它们的内容来加载它们:
dir test*.ps1 | % {iex (gc $_.FullName -Raw)}
Run Code Online (Sandbox Code Playgroud)
现在我们需要认真检查 PowerShell 的工作原理。我喜欢JetBrains dotPeek作为反编译器。如果您曾经尝试在 .NET 应用程序中嵌入 PowerShell,您会发现包含大部分相关内容的程序集是System.Management.Automation. 将那个反编译成一个项目和一个 PDB。
为了查看所有这些神秘的时间都花在了什么地方,我们将使用分析器。我喜欢 Visual Studio 中内置的那个。它非常容易使用。将包含 PDB 的文件夹添加到符号位置。现在,我们可以对仅运行其中一个测试脚本的 PowerShell 实例进行分析运行。(将命令行参数设置为-File与要尝试的第一个脚本的完整路径一起使用。将启动位置设置为包含所有小脚本的文件夹。)完成后,打开powershell.exeTargets 下条目上的 Properties并更改使用其他脚本的参数。然后右键单击性能资源管理器中最上面的项目并选择开始分析. 探查器使用另一个脚本再次运行。现在我们可以比较了。如果有选项,请确保单击“显示所有代码”;对我来说,它显示在示例分析报告的摘要视图中的通知区域中。
在我的机器上,该Get-Content版本需要 9 秒才能浏览 2000 个脚本文件。“热路径”上的重要功能是:
Microsoft.PowerShell.Commands.GetContentCommand.ProcessRecord
Microsoft.PowerShell.Commands.InvokeExpressionCommand.ProcessRecord
Run Code Online (Sandbox Code Playgroud)
这很有意义:我们必须等待Get-Content从磁盘读取内容,我们必须等待Invoke-Expression才能使用这些内容。
在点源版本上,我的机器花了 15 秒多一点的时间来处理这些文件。这一次,Hot Path 上的函数是原生方法:
WinVerifyTrust
CodeAuthzFullyQualifyFilename
Run Code Online (Sandbox Code Playgroud)
第二个似乎没有记录,但WinVerifyTrust“对指定的对象执行信任验证操作”。这几乎是您所能理解的含糊不清,但换句话说,该函数使用给定的提供程序验证给定资源的真实性。请注意,我没有为 PowerShell 启用任何花哨的安全功能,我的脚本执行策略是Unrestricted.
简而言之,您正在等待以某种方式验证每个文件,可能会检查签名,即使当您不限制允许运行的脚本时这不是必需的。当你gc和iex内容时,就像你在控制台输入了函数一样,所以没有资源来验证。
| 归档时间: |
|
| 查看次数: |
806 次 |
| 最近记录: |