PowerShell中命令执行的计时

PowerShell中是否有一种简单的方法来计时命令的执行,就像Linux中的'time'命令一样?< br > 我想出了这个:

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

但我想要简单点的,比如

time .\do_something.ps1
186745 次浏览

是的。

Measure-Command { .\do_something.ps1 }

注意,Measure-Command的一个小缺点是你看不到stdout输出。

[更新,感谢@JasonMArcher]你可以通过将命令输出输出到一些可写入主机的命令集来修复这个问题,例如Out-Default,这样它就变成:

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

查看输出的另一种方法是像这样使用.NET Stopwatch类:

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

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

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

单一的

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

然后可以用as

time { .\some_command }

您可能需要调整输出

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

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的管道允许你看到命令的输出,这是

.否则由Measure-Command消耗

下面是我写的一个函数,它的工作原理类似于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

只是简单地从答案中提到的任何性能度量命令中得出(不正确的)结论。除了查看(自定义)函数或命令的调用时间之外,还应该考虑许多缺陷。

Sjoemelsoftware

< p > 'Sjoemelsoftware'被选为2015年度荷兰语词汇 < br > Sjoemelen的意思是作弊,而sjoemelsoftware这个词是由于大众汽车的尾气排放丑闻而产生的。官方定义是“用于影响测试结果的软件”

就我个人而言,我认为“Sjoemelsoftware”并不总是故意创建来欺骗测试结果,而是可能源于适应类似于下面所示测试用例的实际情况。

例如,使用列出的性能度量命令语言集成查询(LINQ)(1),通常是合格的快速完成某件事的方法,它经常是这样,但肯定不总是这样!任何测量40倍以上与本机PowerShell命令相比速度增加的人,都可能是错误的测量或得出不正确的结论。

关键是一些. net类(如LINQ)使用< >强懒惰评价< / >强(也称为延迟执行(2))。这意味着当将一个表达式分配给一个变量时,它几乎立即看起来完成了,但实际上它还没有处理任何东西!

假设你dot-source你的. .\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

检索$Linq对象的属性比检索$PowerShell对象要长大约系数90,而且那只是一个对象!

还要注意另一个陷阱,如果再次执行,某些步骤可能会比以前快得多,这是因为一些表达式已经被缓存了。

总之,如果希望比较两个函数之间的性能,需要在用例中实现它们,从一个新的PowerShell会话开始,并根据整个解决方案的实际性能得出结论。

< p > (1)关于PowerShell和LINQ的更多背景和例子,我推荐这个网站:高性能PowerShell with LINQ < br > (2)我认为这两个概念之间有一个微小的区别,因为在懒惰的评价中,计算结果是在需要的时候,而不是延迟执行,当系统空闲时时计算结果

到目前为止,所有的答案都无法满足提问者(和我)通过简单地添加“时间”来计算命令时间的愿望。到命令行的开始。相反,它们都需要将命令包装在括号中({})来组成一个块。下面是一个简短的函数,在Unix上的工作方式更像time:

Function time() {
$command = $args -join ' '
Measure-Command { Invoke-Expression $command | Out-Default }
}

一种更受PowerShell启发的方式来访问您关心的属性值:

$myCommand = .\do_something.ps1
Measure-Command { Invoke-Expression $myCommand } | Select -ExpandProperty Milliseconds
    4

As Measure-Command返回一个时间间隔对象。

注意:TimeSpan对象也有TotalMilliseconds作为双变量(如上面我的例子中的4.7322 TotalMilliseconds),这可能对您有用。就像TotalSeconds, TotalDays等。

.totalseconds (measure-commmand{命令})

例如

(measure-commmand {\ do_something.ps1}) .totalseconds