在PowerShell中是否有一种简单的方法来计时命令的执行,就像Linux中的'time'命令一样? 我想到了这个:
$s=Get-Date; .\do_something.ps1 ; $e=Get-Date; ($e - $s).TotalSeconds
但我想要简单点的,比如
time .\do_something.ps1
在PowerShell中是否有一种简单的方法来计时命令的执行,就像Linux中的'time'命令一样? 我想到了这个:
$s=Get-Date; .\do_something.ps1 ; $e=Get-Date; ($e - $s).TotalSeconds
但我想要简单点的,比如
time .\do_something.ps1
当前回答
只是简单地从答案中提到的任何性能度量命令中得出(不正确的)结论。除了查看(自定义)函数或命令的调用时间之外,还应该考虑许多缺陷。
Sjoemel软件
“Sjoemelsoftware”当选2015年荷兰语热词 “Sjoemelen”的意思是“作弊”,“sjoemelsoftware”这个词是由于大众汽车尾气排放丑闻而产生的。官方定义是“用于影响测试结果的软件”。
就我个人而言,我认为“Sjoemelsoftware”并不总是为了欺骗测试结果而故意创建的,而可能是为了适应类似于下面所示的测试用例的实际情况。
例如,使用列出的性能度量命令,语言集成查询(LINQ)(1),通常被认为是完成某件事情的快速方法,而且经常是这样,但肯定不总是这样!与原生PowerShell命令相比,任何测量速度增加了40倍或更多的人都可能是错误的测量或得出了错误的结论。
关键是一些。net类(如LINQ)使用延迟求值(也称为延迟执行(2))。这意味着当将一个表达式分配给一个变量时,它几乎立即看起来完成了,但实际上它还没有处理任何东西!
假设你把你的…做点什么。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
检索$Linq对象的属性比检索$PowerShell对象多花了大约90倍的时间,而且这只是一个对象!
还要注意另一个陷阱,如果再次执行,某些步骤可能会比以前快得多,这是因为一些表达式已经被缓存了。
总之,如果希望比较两个函数之间的性能,需要在用例中实现它们,从一个新的PowerShell会话开始,并根据整个解决方案的实际性能得出结论。
(1)关于PowerShell和LINQ的更多背景和例子,我推荐这个网站:高性能PowerShell with LINQ (2)我认为这两个概念之间有一个微小的区别,因为懒惰计算的结果是在需要时计算的,而延迟执行的结果是在系统空闲时计算的
其他回答
Yup.
Measure-Command { .\do_something.ps1 }
注意,Measure-Command的一个小缺点是看不到标准输出。
[更新,感谢@JasonMArcher]你可以通过将命令输出输出到一些可写入主机的命令集来修复这个问题,例如Out-Default,这样它就变成:
Measure-Command { .\do_something.ps1 | Out-Default }
查看输出的另一种方法是使用。net Stopwatch类,像这样:
$sw = [Diagnostics.Stopwatch]::StartNew()
.\do_something.ps1
$sw.Stop()
$sw.Elapsed
(measure-commmand{your command}).totalseconds
例如
(measure-commmand{.\do_something.ps1}).totalseconds
使用秒表和格式化经过的时间:
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 }
使用Measure-Command
例子
Measure-Command { <your command here> | Out-Host }
到Out-Host的管道允许您查看命令的输出,即 否则由测量命令消耗。
简单的
function time($block) {
$sw = [Diagnostics.Stopwatch]::StartNew()
&$block
$sw.Stop()
$sw.Elapsed
}
然后可以用as
time { .\some_command }
您可能需要调整输出