ChatGPT解决这个技术问题 Extra ChatGPT

在 PowerShell 中计时命令的执行

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

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

但我想要一些更简单的东西,比如

time .\do_something.ps1

O
Oliver

是的。

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

您还可以看到这样的输出,Measure-Command {ps |出默认}。或者其他任何直接写入主机的东西,这可能有用也可能没用。
我采用了这个解决方案并编写了一个可能对其他人有用的函数。 gist.github.com/2206444 -- 示例:time { ping -n 1 google.com } -Samples 10 将运行命令 10 次并返回平均、最短和最长所用时间。您可以添加 -Silent 以吞下 STDOUT。
我的偏好是将 Measure-Command 的结果分配给一个变量,例如 $t = Measure-Command {<<your command or code block>>} 。试一试,然后在提示符处键入 $t 以查看您的结果以及您有权访问的所有属性,例如 $t.Milliseconds$t.TotalSeconds 等。然后我们可以写入我们想要的任何输出,例如,{ 5}
用什么更快? net.stopwatch,或测量命令,或只是比较两个获取日期变量......(我的意思是永久保存在脚本中更有效?)
| Out-Default 类似,您也可以使用 -OutVariable 来存储输出对象,例如 $m = Measure-Command { Get-WinEvent -LogName System -MaxEvents 1 -OutVariable events }; $events.Message; $m.TotalSeconds
b
bdukes

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

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

试试这个:Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -desc 按一天中的小时查看您的 PowerShell 使用模式。 :-)
+1 能够使用它来找出某件事花费了多长时间,即使您在开始时没想到它会花费很长时间,因此您没有考虑将其包装在 Measure-Command 中。
powershell 有时很棒。
是的,这太棒了!我使用:$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
重要说明,我不知道这在 10 年有多真实,但在此评论之前的某个时间点,命令对象有一个“持续时间”字段,因此不再需要从两个 FooExecutionTime 字段手动计算。
t
thegreendroid

使用Measure-Command

例子

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

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


我认为您的意思是 Measure-Command {<your command } | Out-Host - Out-Host 在脚本块之外
@Peter - 它需要在块内,否则 Measure-Command 在输出到控制台之前会消耗输出。
明白了......在那种情况下,你甚至可能不需要管道。它应该只打印结果,除非你将它包装在其他块中......
由于与脚本兼容,Out-Default 是否可能比 Out-Host 更好? jsnover.com/blog/2013/12/07/write-host-considered-harmful
好吧,我尝试了 Out-Default 并且它在终端中也可以正常工作,那么为什么不总是使用 Out-Default 呢? (对不起,我没有在脚本中尝试过)
M
Mike West

简单的

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

然后可以用作

time { .\some_command }

您可能需要调整输出


Measure-Command 隐藏命令输出,因此此解决方案有时更好。
这是一个很棒的解决方案,它尊重命令的输出。您也可以在没有花括号的情况下为简单命令调用它,例如:“time ls”,就像在 Unix 中一样。
我用它来测量函数调用。但是,您最好将参数也添加到调用约定中,例如:& $block @Args
B
Bender

这是我编写的一个函数,其工作方式类似于 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 为进程计时有什么关系?
这是我编写的一个 Powershell 函数,它展示了如何自己计算执行时间,而不是使用 Measure-Command 或您可以在 Powershell 中计时执行的各种其他方法之一。如果您阅读原始问题,他会要求一些“类似于 Linux 中的 time 命令”的东西。
K
Kiquenet

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

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 }

J
John Freeman

到目前为止,所有答案都没有达到提问者(和我)通过简单地在命令行开头添加“时间”来为命令计时的愿望。相反,它们都需要将命令括在方括号 ({}) 中以生成块。这是一个在 Unix 上更像 time 的简短函数:

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

M
MaxCreatesCode

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

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

因为 Measure-Command 返回一个 TimeSpan 对象。

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


J
JamesNEW

(measure-commmand{你的命令}).totalseconds

例如

(测量命令{.\do_something.ps1}).totalseconds


i
iRon

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

Sjoemel 软件

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

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

例如,使用列出的性能测量命令 Language Integrated Query (LINQ)(1) 通常被认为是完成某事的禁食方法,而且通常是,但肯定是不总是!任何人如果测量与原生 PowerShell 命令相比 40 倍或更多 的速度增加,则可能是在错误地测量或得出错误的结论。

关键是某些 .Net 类(如 LINQ)使用 lazy evaluation(也称为延迟执行(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 会话开始,并将您的结论基于完整解决方案的实际性能。

(1) 有关 PowerShell 和 LINQ 的更多背景知识和示例,我推荐 tihis 站点:High Performance PowerShell with LINQ
(2) 我认为这两个概念之间存在细微差别惰性评估结果是在需要时计算的,与延迟执行是在系统空闲时计算结果 >


此答案的目的是让人们能够参考一个常见问题,以解决关于 PowerShell 中的 计时命令 的一般误解,就像我刚刚针对类似的重复问题所做的那样:Powershell question - Looking for fastest method to loop through 500k objects looking for a match in another 500k object array