为什么 Powershell 这么慢?

Nei*_*ir0 13 performance powershell

我试图用 PowerShell 做一个简单的事情,找到占用驱动器大部分空间的文件。我使用了ls+sort并且......对我来说花了很长时间。

有时我使用远管理器,与 PowerShell 相比,它看起来更快更稳定。

好吧,它是基于 .NET 的,但是 .NET 并没有那么慢。我希望看到轻量级和快速的东西!是控制台!

另一件事,我想IEnumerable在 PowerShell 中使用类似的东西来立即查看结果。有可能实现吗?在期待结果时它可能会有所帮助,因为有时我认为它只是闲逛。

编辑

我正在做类似的事情

ls -Recurse -ErrorAction SilentlyContinue | sort -Property Size | select -First 10
Run Code Online (Sandbox Code Playgroud)

我想这可能需要几天时间。

编辑

只是为了比较。

C# 代码花了我大约 2 分钟。当然它并不理想并且没有处理所有文件,但它至少处理了> 95%。

ls -Recurse -ErrorAction SilentlyContinue | sort -Property Size | select -First 10
Run Code Online (Sandbox Code Playgroud)

Fra*_*mas 15

PowerShell 是一个用 .Net 编写的程序,但它在实际运行时利用了许多不同解释器和运行时的接口。它是一个 Shell,所以就像 BASH 一样,即使它是用 C 编写的,也没有说明在其中执行的二进制文件和脚本。可执行文件可能是 .Net 代码、VDM/CMD 命令、*nix shell 命令、VB/C/WSScript、WMI 调用、非托管 API 接口、jar 文件或其他任何东西。这些选择会影响在 shell 中运行的代码的性能,而不是 shell 所用的语言。

现在,听起来您在执行特定命令时遇到了困难。所以更好的问题是,为什么ls从 PowerShell 中调用时排序很慢。当我们深入挖掘时,我们发现它ls是“Get-ChildItem”的别名,它返回一个包含 System.IO.DirectoryInfo 对象的对象数组。

PS C:\Windows\system32> $x=Get-ChildItem ./
PS C:\Windows\system32> $x.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array 

PS C:\Windows\system32> $x[1].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DirectoryInfo                            System.IO.FileSystemInfo   

PS C:\Windows\system32>
Run Code Online (Sandbox Code Playgroud)

您可以检索ls结果,然后将其通过管道传输到Sort-Object 调用中,它的行为在很大程度上与 IEnumerable 相同。

请注意, IEnumerable 不会为性能做任何事情。您可能会将它与 IQueryable 混淆,后者定义但直到最后一秒才执行查询,大概是在使用过滤和排序操作修饰之后,就像 .Net 通过 LinQ to Objects 所做的那样。在这种情况下,由于 Get-ChildItem 不提供优化的查询引擎或索引数据源,因此您无法真正将现代数据库操作与目录列表进行比较。

因此,最终,请尝试以下操作: ls ./ -recurse | Sort-Object Name -descending 对我而言,针对 System32,这需要大约 20 秒来处理和排序 54430 个文件。

最后,请注意,当您尝试枚举您个人无权访问的目录时,您的性能会受到很大影响,因此请确保您没有递归到不允许去的地方,否则您将遭受 2 + 第二次等待。

希望有帮助。


Tes*_*ler 10

PowerShell 旨在方便而不是快速。这是一个权衡——它确实在幕后工作,所以用户必须做的更少。做更多的工作会使它变慢。

看到你的 PowerShell 代码是一行,比你的 C# 代码在 15 行中做的更多。

它做得更多 - 即使您没有使用它。

ls在 Linux 上返回字符串,字符串简单快速。您的 .Net 代码甚至不保留文件名,它只保留大小,并且数字再次变小,因此速度更快

ls 在 PowerShell 中,返回 [FileInfo] 和 [DirectoryInfo] 对象 - 每个对象都必须创建,每个对象都必须查询文件以填写其他字段,如 CreationTime 和 LastWriteTime 以及 Extension 和 Length,并且必须创建时间字段[日期时间] 对象。

对于每个文件,这都会慢很多。启用其他选项的成本,即使您不使用它们 - 您的 PowerShell 代码可能会更改为使用 1 月份创建的前 10 个文件的大小,只需进行简单更改,无需其他 cmdlet 或工具,并且仍然是一行, C# 代码必须被大量重写,查询创建时间,将创建时间和大小都带入排序,等等。

您没有立即看到结果的原因是因为您| sort. 这让它变得不可能。如果您立即开始输出结果,但找到的最后一个文件需要排在最前面怎么办?那么输出将是错误的 - IEnumerable 对此无能为力,| sort必须先收集每个输入才能输出任何内容。您的排序速度更快,因为它正在对小东西进行排序

您的 .Net 代码可以更快地自行进行排序,因为它正在对 [long] 的枚举进行排序,而无需进行任何属性查找。

总的来说,你的代码做的少了很多,做的更少花费的时间也更少。但是你写的时间更长,灵活性也更差,重点也更窄。一种权衡。