在PowerShell中定时执行命令


217

是否有一种简单的方法来计时PowerShell中命令的执行时间,例如Linux中的“时间”命令?
我想出了这个:

$s=Get-Date; .\do_something.ps1 ; $e=Get-Date; ($e - $s).TotalSeconds

但我想要更简单的东西

time .\do_something.ps1

Answers:


337

对。

Measure-Command { .\do_something.ps1 }

请注意,它的一个小缺点Measure-Command是您看不到任何stdout输出。

[更新,感谢@JasonMArcher]您可以通过将命令输出传递到写入主机的某些Commandlet中来解决此问题,例如Out-Default,它将变为:

Measure-Command { .\do_something.ps1 | Out-Default }

查看输出的另一种方法是使用.NET Stopwatch类,如下所示:

$sw = [Diagnostics.Stopwatch]::StartNew()
.\do_something.ps1
$sw.Stop()
$sw.Elapsed

114
您还可以通过Measure-Command {ps | 默认值}。或直接写入主机的任何其他内容,可能有用也可能没有用。
JasonMArcher

18
我采用了此解决方案,并编写了对其他人可能有用的函数。gist.github.com/2206444-示例:time { ping -n 1 google.com } -Samples 10将运行命令10时间并返回平均,最小和最大时间。您可以添加-Silent吞咽STDOUT。
joshuapoehls 2012年

13
我的偏好是将Measure-Command的结果分配给变量,例如$t = Measure-Command {<<your command or code block>>}。试试吧,然后键入$t在提示符下查看结果和所有您可以访问,如性能$t.Milliseconds$t.TotalSeconds等等。然后我们可以写信给我们想要的任何输出,例如,Write-Host That command took $t.TotalSeconds to complete.
Baodad

使用什么更快?net.stopwatch或measure-command,或仅比较两个get-date var ...(我的意思是,永久保存在脚本中更有效吗?)
Hicsy

也许包括JasonMArcher的评论要点(因此很显然,它可以比整个PowerShell脚本更细粒度地使用)?
彼得·莫滕森

183

您还可以从历史记录中获取最后一个命令,并EndExecutionTime从中减去它StartExecutionTime

.\do_something.ps1  
$command = Get-History -Count 1  
$command.EndExecutionTime - $command.StartExecutionTime

22
有时Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -desc,请尝试以下操作:按小时查看您的PowerShell使用模式。:-)
基思·希尔

18
+1是为了能够使用它来找出某事物花费了多长时间,即使您不希望它在开始时花费很长时间也是如此,因此您不打算将其包装在Measure-Command中。
克里斯·马格努森

3
powershell有时很棒。
ConstantineK

我希望我能给您的不仅仅是+1 :)
David FerenczyRogožan18年

是的,太好了!我使用以下方法制作了$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

Measure-Command

Measure-Command { <your command here> | Out-Host }

的管道Out-Host允许您查看命令的输出,否则将被使用Measure-Command


我认为您的意思是Measure-Command {<your command } | Out-Host -外主机不在脚本块内
Peter McEvoy

1
@Peter-它必须位于该块内,否则Measure-Command在将其输出到控制台之前会消耗其输出。
德罗伊(Droj)

1
要知道...在这种情况下,您甚至可能不需要管道。除非您将结果包裹在其他块中,否则它应该只打印结果
。...– Droj

2
因为与脚本兼容,所以默认默认值是否可能优于默认主机?jsnover.com/blog/2013/12/07/write-host-considered-harmful
MarcH

1
好吧,我尝试了Out-Default,它在终端中也可以正常工作,所以为什么不总是使用Out-Default?(抱歉,我没有在脚本中尝试过)
MarcH

18

简单的

function time($block) {
    $sw = [Diagnostics.Stopwatch]::StartNew()
    &$block
    $sw.Stop()
    $sw.Elapsed
}

然后可以用作

time { .\some_command }

您可能需要调整输出


1
Measure-Command隐藏命令输出,因此此解决方案有时会更好。
codekaizen

这是一个很棒的解决方案,它尊重命令的输出。您也可以不带花括号地调用它来使用简单命令,例如:“ time ls”,就像在Unix中一样。
劳尔·萨利纳斯-蒙塔古多

5

这是我编写的与Unix time命令类似的功能:

function time {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$command,
        [switch]$quiet = $false
    )
    $start = Get-Date
    try {
        if ( -not $quiet ) {
            iex $command | Write-Host
        } else {
            iex $command > $null
        }
    } finally {
        $(Get-Date) - $start
    }
}

资料来源:https : //gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874


问题是“在PowerShell中为命令执行计时”。这与使用Unix计时进程有什么关系?
Jean-Claude DeMars

5
这是我编写的Powershell函数,它显示了如何自己计算执行时间,而不是使用Measure-Command或在Powershell中计时执行时间的其他方式之一。如果您阅读了原始问题,那么他会问一些“类似于timeLinux中的命令”的东西。
本德尔最伟大的

3

使用秒表和格式化经过的时间:

Function FormatElapsedTime($ts) 
{
    $elapsedTime = ""

    if ( $ts.Minutes -gt 0 )
    {
        $elapsedTime = [string]::Format( "{0:00} min. {1:00}.{2:00} sec.", $ts.Minutes, $ts.Seconds, $ts.Milliseconds / 10 );
    }
    else
    {
        $elapsedTime = [string]::Format( "{0:00}.{1:00} sec.", $ts.Seconds, $ts.Milliseconds / 10 );
    }

    if ($ts.Hours -eq 0 -and $ts.Minutes -eq 0 -and $ts.Seconds -eq 0)
    {
        $elapsedTime = [string]::Format("{0:00} ms.", $ts.Milliseconds);
    }

    if ($ts.Milliseconds -eq 0)
    {
        $elapsedTime = [string]::Format("{0} ms", $ts.TotalMilliseconds);
    }

    return $elapsedTime
}

Function StepTimeBlock($step, $block) 
{
    Write-Host "`r`n*****"
    Write-Host $step
    Write-Host "`r`n*****"

    $sw = [Diagnostics.Stopwatch]::StartNew()
    &$block
    $sw.Stop()
    $time = $sw.Elapsed

    $formatTime = FormatElapsedTime $time
    Write-Host "`r`n`t=====> $step took $formatTime"
}

使用样本

StepTimeBlock ("Publish {0} Reports" -f $Script:ArrayReportsList.Count)  { 
    $Script:ArrayReportsList | % { Publish-Report $WebServiceSSRSRDL $_ $CarpetaReports $CarpetaDataSources $Script:datasourceReport };
}

StepTimeBlock ("My Process")  {  .\do_something.ps1 }

-2

只需回答答案中提到的任何性能测量命令中的结论(错误)即可。除了查看(自定义)函数或命令的裸调用时间外,还应考虑许多陷阱。

Sjoemel软件

“ Sjoemelsoftware”在荷兰语中被评为2015年度单词
Sjoemelen意味着作弊,而 sjoemelsoftware这个词是由于大众汽车排放丑闻而出现的。官方定义是“用于影响测试结果的软件”。

我个人认为,并非总是故意创建“ Sjoemelsoftware ”来欺骗测试结果,但可能源于与如下所示的测试案例相似的实际适应情况。

作为一个例子,使用列出的性能测量命令,语言集成查询(LINQ)(1) ,往往是作为合格禁食方式得到的东西做,它往往是,但肯定不是永远!与本地PowerShell命令相比,将速度提高40倍或更多的人,可能是错误地测量或得出了错误的结论。

关键是某些.Net类(如LINQ)使用了惰性求值(也称为延迟执行(2))。这意味着在将表达式分配给变量时,几乎可以立即完成该操作,但实际上它尚未处理任何操作!

让我们假定你点源. .\Dosomething.ps1命令,它有两种PowerShell的或更复杂的LINQ表达式(为了便于说明,我已经直接直接嵌入表达式为Measure-Command):

$Data = @(1..100000).ForEach{[PSCustomObject]@{Index=$_;Property=(Get-Random)}}

(Measure-Command {
    $PowerShell = $Data.Where{$_.Index -eq 12345}
}).totalmilliseconds
864.5237

(Measure-Command {
    $Linq = [Linq.Enumerable]::Where($Data, [Func[object,bool]] { param($Item); Return $Item.Index -eq 12345})
}).totalmilliseconds
24.5949

结果看起来很明显,后面的Linq命令比第一个PowerShell命令快40倍。不幸的是,这不是那么简单...

让我们显示结果:

PS C:\> $PowerShell

Index  Property
-----  --------
12345 104123841

PS C:\> $Linq

Index  Property
-----  --------
12345 104123841

正如预期的那样,结果是相同的,但是如果您密切关注,您将发现显示$Linq结果比显示结果花费了更长的时间$PowerShell
让我们通过仅检索结果对象的属性来专门测量

PS C:\> (Measure-Command {$PowerShell.Property}).totalmilliseconds
14.8798
PS C:\> (Measure-Command {$Linq.Property}).totalmilliseconds
1360.9435

检索对象的属性要比该对象花费更长的时间90倍,而这仅仅是一个对象!$Linq$PowerShell

还要注意另一个陷阱,如果您再次执行此操作,某些步骤的显示速度可能比以前快很多,这是因为某些表达式已被缓存。

最重要的是,如果要比较两个功能之间的性能,则需要在用例中实现它们,从全新的PowerShell会话开始,然后基于完整解决方案的实际性能得出结论。

(1)有关详细的背景和PowerShell和LINQ的例子,我建议tihis网站:高性能PowerShell和LINQ
(2)我认为有两个概念之间是有微小的差别懒惰评估结果计算需要的时候为并列于系统空闲时计算结果的时间推迟执行


这个答案的目的是使人们能够就PowerShell中的计时命令向人们提出一个普遍的误解,就像我对一个重复的问题所做的那样:Powershell问题-寻找循环50万个对象的最快方法在另一个500k对象数组中寻找匹配项
iRon
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.