PowerShell cmdlet 与 .NET class

A PowerShell cmdlet vs. a .NET class

编写 PowerShell 脚本时,有两种选择:

  1. 打电话给cmdlet
  2. 使用.NET Framework Class library

在后台,cmdlet 可能更多地使用了 .NET 库。

在性能方面,两者中哪一个更适合在 Powershell 脚本中使用?

我更喜欢直接使用 .NET 库,因为它更接近 C#。

两者之间的差异应该很小。该 cmdlet 将调用 .NET Framework 方法,因此行为将相同。

因此,如果不使用 cmdlet,您可能会看到一些极其微小的性能改进;但可以忽略不计。

为什么不考虑哪个读起来更好并坚持下去?

When writing a Powershell script, two options are available:

  1. Call a cmdlet
  2. Use the .NET Framework Class library

TBH,我认为这是对 PowerShell 的过度简化。

首先值得指出的是 PowerShell(API powershell.exe 主机应用程序)首先是在 .NET 中实现的,所以根据定义,PowerShell 中的所有内容都是 "using .NET".

例如,一个 cmdlet 实际上是一个 .NET 对象 - 看看 Get-Command:

返回的 CmdletInfo 对象
PS C:\> (Get-Command Get-Command) |Format-List Name,CommandType,DLL,ImplementingType


Name             : Get-Command
CommandType      : Cmdlet
DLL              : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad36
                   4e35\System.Management.Automation.dll
ImplementingType : Microsoft.PowerShell.Commands.GetCommandCommand

查看实现类型 Microsoft.PowerShell.Commands.GetCommandCommand - 它只是一个常规的 .NET class - 当你发出命令 Get-Command 时,powershell 会创建这个 class,调用一些定义明确的方法,然后调用执行实际工作的 .NET 方法。


PowerShell(或 Monad, as it was originally called)背后的整个理念是,开发时间最好花在专注于做好一件事的小型独立 units/functions(monad 在原始概念中),很像 UNIX 实用程序背后的原始哲学。

这个想法是,一旦您有了一个将这些单元耦合在一起的框架,您实际上可以通过连接更简单的单元来编写任何程序。

这个想法的具体化是 cmdlet - 它有一些明确定义的输入绑定行为,允许您编写 管道

Get-AThing | Filter-TheThing | Write-ToAFile C:\path\to\file\name.ext

以我的愚见,像上面这样的管道 way 比例如

更具可读性
[System.IO.File]::WriteAllText('C:\path\to\file\name.ext', [System.Linq.Enumerable]::Select([Thing]::EnumerateThings(),{param([thing]$in) $in -eq $someCriteria}))

这是主观的,但我想表达的是,如果您顺便放弃 cmdlet,您就是在欺骗自己,利用 PowerShell 免费提供的一些开箱即用的核心功能-边


现在,对于真正的问题:是的,直接调用单个 .NET 方法比调用 cmdlet 更快并且产生的开销更少,这反过来又使 PowerShell 运行 一些额外的代码最终只是包装相同的.NET 方法调用。

也就是说,如果您运行使用较新版本的 PowerShell(4.0、5.0、5.1 或 6.0),在许多情况下开销可以忽略不计。

例如,从磁盘读取文件比解决已经在内存中的一系列 .NET 方法调用要慢几个数量级(这是 PowerShell 对您透明地做的事情),仅仅是因为将电子从通过磁盘控制器和内存总线将磁盘旋转到内存中是一种受光速限制的操作。

我个人的性能优化策略是回顾 algorithms/routines 和我使用的数据结构,远在我开始考虑 cmdlet 与直接方法调用之前。

如果我在做一些愚蠢的事情,使我的脚本需要 10 倍的 CPU 周期来计算,那么尝试追逐边际开销将无济于事。

如果您已达到该策略的极限,请考虑用 C# 或 VB.NET 编写您的 cmdlet - 编译代码(几乎)总是比解释代码快 :-)

对我来说,在使用了两者之后,选择真正归结为代码维护。脚本化的 cmdlet 允许更轻松地管理 类 的代码维护,并且有结构化的重新编译和发布。

脚本化的 cmdlet 每次都是我的选择,除非处理速度很关键。