PowerShell性能差异过滤器与功能


11

我目前正在阅读Windows PowerShell 3.0循序渐进书,以获得对PowerShell的更多了解。

在第201页上,作者演示了过滤器比具有相同功能的函数要快。

此脚本在他的计算机上需要2.6秒:

MeasureAddOneFilter.ps1
Filter AddOne
{ 
 "add one filter"
  $_ + 1
}

Measure-Command { 1..50000 | addOne }

而这4.6秒

MeasureAddOneFunction.ps1
Function AddOne
{  
  "Add One Function"
  While ($input.moveNext())
   {
     $input.current + 1
   }
}

Measure-Command { 1..50000 | addOne }

如果我运行此代码,则得到与他的结果完全相反的结果:

.\MeasureAddOneFilter.ps1
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 226
Ticks             : 2266171
TotalDays         : 2,62288310185185E-06
TotalHours        : 6,29491944444444E-05
TotalMinutes      : 0,00377695166666667
TotalSeconds      : 0,2266171
TotalMilliseconds : 226,6171

.\MeasureAddOneFunction.ps1

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 93
Ticks             : 933649
TotalDays         : 1,08061226851852E-06
TotalHours        : 2,59346944444444E-05
TotalMinutes      : 0,00155608166666667
TotalSeconds      : 0,0933649
TotalMilliseconds : 93,3649

谁可以给我解释一下这个?

Answers:


13

除非作者提供更多的支持证据,否则他可能洋洋得意。您已经运行了测试并获得了结果,并证明他是错误的。

编辑:从Jeffrey Snover的博客:

过滤器是仅具有过程脚本块的函数

仅仅这还不足以说服我一个过滤器相对于一个函数在速度上具有优势,因为它们都具有相同的处理块。

那家伙在哪种1950年代的设备上加一个数字需要4.6秒?

PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 7.7266


PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 0.4108

4.6秒是重击。也许在二进制生成之前,作者正在使用某种CTP版本的Powershell。:P

最后,以相反的顺序在新的Powershell会话中尝试测试。首先尝试功能,然后尝试过滤器,反之亦然:

PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 6.597    


PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 0.4055

看到?您运行的第一个总是较慢。正是.NET内部已经将内容加载到内存中,这使得第二个操作更快,而不管它是函数还是过滤器。

我将承认,尽管该函数运行了多少次,但它似乎始终比过滤器更快。

Measure-Command { Function AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 13.9813

Measure-Command { Filter AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 69.5301

所以作者错了...现在,对于以前从未使用过Filter而不是Function的人,我并不感到难过。


4

实际上,如果在两个测试中使用相同的$ _,则差异要小得多。我没有调查原因,但我想是因为作者在两种测试中使用的方法都不相同。此外,控制台输出可能会干扰结果。如果切割这些零件,则数字非常相似。看到:

Function AddOneFunction
{  
    process {
        $_ + 1
    }
}

Filter AddOneFilter
{ 
    $_ + 1
}

write-host "First"
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds

write-host "Second"
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds

即使更改命令的顺序,结果也将非常接近。

First

TotalMilliseconds
-----------------
        84.6742
        84.7646
        89.8603
        82.3399
        83.8195
Second
        86.8978
        87.4064
        89.304
        94.4334
        87.0135

该文档还说,过滤器基本上是仅具有流程块的功能的快捷方式。除非使用过程块指定功能(或使用诸如$ input之类的自动变量之类的其他技术)指定功能,否则它们只能运行一次,不要使用输入,也不要传递给管道中的下一个命令。

有关更多信息,访问https://technet.microsoft.com/en-us/library/hh847829.aspxhttps://technet.microsoft.com/en-us/library/hh847781.aspx

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.