点源采购是否比仅读取文件内容还要慢?


13

我编写了一个PowerShell模块,该模块从不同的源文件(即每个函数一个.ps1文件)中提取函数定义。这使我们(作为一个团队)可以并行处理不同的功能。模块(.psm1文件)获取可用.ps1文件的列表...

$Functions = Get-ChildItem -Path $FunctionPath *.ps1

...然后遍历列表并通过点源引入每个函数定义:

foreach($Function in $Functions) {
  . $Function.Fullname                                     # Can be slow
}

问题:我们注意到完成速度大约有10到180秒(大约50个源文件)变化很大,这取决于我们在哪台机器上进行测试。我们无法解释所花费时间的巨大差异,并且相信我们已经控制了变量,例如机器类型,操作系统,用户帐户,管理员权限,PS配置文件,PS版本等。相同主机在同一主机上花费的时间可能有所不同用户从一天到第二天。

我们确实想知道这是否与磁盘访问有关,并测试了我们可以从磁盘中读取数据的速度。事实证明,Get-Content在所有这些文件上运行都非常快,我们在解决该问题的方法中利用了这一点:

foreach($Function in $Functions) {
  Invoke-Expression (Get-Content $Function.Fullname -Raw)  # Is quick
}

为什么通过点源添加这些功能比读取和执行文件内容要慢得多?

Answers:


17

建立科学

首先,一些脚本可以帮助我们进行测试。这将生成2000个脚本文件,每个脚本文件都有一个小功能:

1..2000 | % { "Function Test$_(`$someArg) { Return `$someArg * $_ }" > "test$_.ps1" }

这应该足以使正常的启动开销无关紧要。您可以根据需要添加更多内容。这使用点源将它们全部加载:

dir test*.ps1 | % {. $_.FullName}

首先通过读取它们的内容来加载它们:

dir test*.ps1 | % {iex (gc $_.FullName -Raw)}

现在,我们需要对PowerShell的工作方式进行认真检查。我喜欢JetBrains dotPeek作为反编译器。如果您曾经尝试将PowerShell嵌入.NET应用程序,则会发现包含大多数相关内容的程序集是System.Management.Automation。将其反编译为项目和PDB。

为了了解所有这些神秘的时间在哪里度过,我们将使用探查器。我喜欢Visual Studio中内置的那个。它非常易于使用。将包含PDB的文件夹添加到符号位置。现在,我们可以对只运行其中一个测试脚本的PowerShell实例进行性能分析。(设置命令行参数以尝试使用-File第一个脚本的完整路径。将启动位置设置为包含所有小脚本的文件夹。)完成后,powershell.exe在“目标”下的条目上打开“属性” 并更改使用其他脚本的参数。然后右键单击Performance Explorer中最上面的项目,然后选择“ 开始分析”。探查器使用其他脚本再次运行。现在我们可以进行比较。如果提供选项,请确保单击“显示所有代码”;对我来说,它显示在“样本分析报告”的“摘要”视图中的“通知”区域中。

结果进来

在我的计算机上,该Get-Content版本花费了9秒钟来浏览2000个脚本文件。“热路径”上的重要功能是:

Microsoft.PowerShell.Commands.GetContentCommand.ProcessRecord
Microsoft.PowerShell.Commands.InvokeExpressionCommand.ProcessRecord

这很有意义:我们必须等待Get-Content从磁盘读取内容,并且必须等待Invoke-Expression利用这些内容。

在点源版本中,我的机器花了超过15秒钟来浏览这些文件。这次,Hot Path上的函数是本机方法:

WinVerifyTrust
CodeAuthzFullyQualifyFilename

那里的第二个似乎没有记录,但是WinVerifyTrust“对指定对象执行信任验证操作”。这大约是您所能理解的,但是换句话说,该函数使用给定的提供程序来验证给定资源的真实性。请注意,我尚未为PowerShell启用任何高级安全功能,我的脚本执行策略为Unrestricted

那意味着什么

简而言之,您正在等待以某种方式验证每个文件,可能检查了签名,即使在不限制允许运行的脚本时也不必这样做。当你gciex的内容,它就像你输入在控制台的功能,所以没有资源来验证。


2
本,感谢您的出色回答。给您留下深刻印象,您可以进行反编译,这是我尝试过的任何步骤。我将看看是否有任何方法可以在其中一台最严重此问题的机器上遵循您的测试方法。这可能需要一段时间,所以请不要屏住呼吸!
查理·乔伊特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.