使用管道和直接使用InputObject参数之间的效率差异?

时间:2018-10-18 02:57:00

标签: powershell

这里是一个示例,我有一个名为“ s1”的远程服务器,我想杀死其中的calc,记事本和winword进程。

我可能有两种方法可以做到这一点,

  1. 使用管道

Get-Process -computername s1 -name "calc", "notepad", "winword" | Stop-Process

  1. 使用InputObject参数

$processes = Get-Process -computername s1 -name "calc", "notepad", "winword" Stop-Process -InputObject $processes

IMO,我认为第二种方法比第一种更好。

据说PowerShell中的管道实际上将对象一一传递给以下Cmdlet。在这种情况下,停止进程需要多次与远程计算机“ s1”进行通信,并逐个杀死这些进程。

相比之下,第二种方式,我想Stop-Process只会与远程计算机“ s1”通信,一次并一次完成操作。

我理解正确吗?

谢谢

马丁

1 个答案:

答案 0 :(得分:2)

关于远程方面

您应该完全选择其他方法:使用Invoke-Command 远程运行整个管道:

Invoke-Command -ComputerName s1 { 
  Get-Process -Name 'calc', 'notepad', 'winword' | Stop-Process
}

但是请注意,Invoke-Command(PSv3 +)要求在目标计算机上配置 PowerShell远程处理(请参阅Get-Help about_Remote_FAQ),而Get-Process cmdlet使用远程处理的另一种过时形式。

实际上,当我在两台v5.1机器之间尝试您的方法时,本地运行的Stop-Process命令试图对远程过程对象失败进行操作,并出现以下错误:< / p>

Cannot stop process "<name>" because of the following error:
Feature is not supported for remote machines.

通常,最好的方法是尽可能远地执行尽可能多的处理,并将结果仅传输到本地计算机


关于管道输入与通过-InputObject进行输入的更一般方面:

使用-InputObject传递集合(Get-Foo -InputObject $collection)肯定比通过管道($collection | Get-Foo)发送该集合要快,但请注意需要将整个输入集合整体加载到内存中 ,这有可能抵消管道的一项主要优势:内存限制

请注意,使用-InputObject通常不是 管道输入的可行替代方法,因为许多cmdlet 不枚举集合您传递给-InputObject(将1, 2 | ForEach-Object { "[$_]" }ForEach-Object { "[$_]" } -InputObject 1, 2进行比较);通常,这是偶然发生的,它们使用不是{em> arrays 的-InputObject声明,但有时是设计使然:Get-Member cmdlet故意不枚举传递给{ {1}},因为它随后检查了集合的类型,而不是其元素的类型。有关背景信息,请参见this GitHub issue

还请注意,如果还有其他流水线段(-InputObject),则在输出再次进行流式传输(一对一处理)。

您可以使用Get-Foo -InputObject ... | ... 语句foreach)代替管道,从而加快逐项处理的速度,但是如果您可以避免在循环正文中调用cmdlet,则只有这样才有效。
但是,与foreach ($elem in $collection) { ... }一样,此要求将整个输入集合整体加载到内存中
>


使用Time-Command,对10,000个输入对象(平均100次运行)进行性能比较:

-InputObject

示例计时(Windows 10上的Windows PowerShell 5.1,单核VM):

$collection = 1..10000
Time-Command -Count 100 { $collection | Write-Output }, 
                        { Write-Output -InputObject $collection },
                        { foreach ($o in $collection) { $o } }
  • Command Secs (100-run avg.) TimeSpan Factor ------- ------------------- -------- ------ foreach ($o in $collection) { $o } 0.010 00:00:00.0103421 1.00 Write-Output -InputObject $collection 0.015 00:00:00.0152200 1.47 $collection | Write-Output 0.108 00:00:00.1076183 10.41 是最快的(请注意循环主体中如何依赖 implicit 输出:如果使用了foreach调用,那将是最慢的)解决方案),其性能{@ {1}}紧随其后;有趣的是,这些角色在PowerShell Core 中似乎是颠倒的
  • 通过管道提供输入的速度慢了大约10倍。

但是,请注意,这些因素会随输入集合(可能还有您的硬件)的大小而变化。