Thời gian thực hiện lệnh trong PowerShell


217

Có cách nào đơn giản để tính thời gian thực hiện lệnh trong PowerShell, như lệnh 'time' trong Linux không?
Tôi nghĩ ra cái này:

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

Nhưng tôi muốn một cái gì đó đơn giản hơn như

time .\do_something.ps1

Câu trả lời:


337

Vâng

Measure-Command { .\do_something.ps1 }

Lưu ý rằng một nhược điểm nhỏ Measure-Commandlà bạn không thấy stdoutđầu ra.

[Cập nhật, nhờ @JasonMArcher] Bạn có thể khắc phục điều đó bằng cách chuyển đầu ra lệnh tới một số lệnh ghi vào máy chủ, ví dụ: Out-Defaultnó trở thành:

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

Một cách khác để xem đầu ra sẽ là sử dụng Stopwatchlớp .NET như thế này:

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

114
Bạn cũng có thể thấy đầu ra như thế này, Biện pháp-Lệnh {ps | Ngoài mặc định}. Hoặc bất cứ điều gì khác viết trực tiếp đến máy chủ lưu trữ, có thể có hoặc không hữu ích.
JasonMArcher

18
Tôi lấy giải pháp này và viết một chức năng có thể hữu ích cho người khác. gist.github.com/2206444 - Ví dụ: time { ping -n 1 google.com } -Samples 10sẽ chạy 10thời gian lệnh và trả về thời gian trung bình, tối thiểu và tối đa được thực hiện. Bạn có thể thêm -Silentđể nuốt STDOUT.
joshuapoehls

13
Sở thích của tôi sẽ là gán kết quả của Lệnh-Lệnh cho một biến, như thế nào $t = Measure-Command {<<your command or code block>>}. Hãy thử nó ra và sau đó gõ $ttại dấu nhắc để xem kết quả của bạn và tất cả các thuộc tính bạn có thể truy cập, giống như $t.Milliseconds, $t.TotalSeconds, vv Sau đó, chúng ta có thể viết thư cho bất cứ điều gì chúng tôi muốn đầu ra, ví dụ,Write-Host That command took $t.TotalSeconds to complete.
Baodad

Những gì nhanh hơn để sử dụng? net.stopwatch, hoặc chỉ huy đo lường, hoặc chỉ so sánh hai vars ngày hẹn hò ... (ý tôi là cái gì hiệu quả hơn để giữ vĩnh viễn trong một kịch bản?)
Hicsy

Có lẽ bao gồm ý chính của nhận xét của JasonMAriner (vì vậy rõ ràng nó có thể được sử dụng theo cách chi tiết hơn so với toàn bộ tập lệnh PowerShell)?
Peter Mortensen

183

Bạn cũng có thể nhận lệnh cuối cùng từ lịch sử và trừ nó EndExecutionTimetừ lệnh đó StartExecutionTime.

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

22
Thỉnh thoảng hãy thử điều này: Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -descđể xem mẫu sử dụng PowerShell của bạn theo giờ trong ngày. :-)
Keith Hill

18
+1 để có thể sử dụng điều này để tìm hiểu xem một cái gì đó đã mất bao lâu ngay cả khi bạn không mong đợi nó sẽ mất nhiều thời gian khi bạn bắt đầu để bạn không nghĩ sẽ bọc nó trong Biện pháp Chỉ huy.
Chris Magnuson

3
powershell đôi khi là tuyệt vời.
ConstantineK

Tôi ước tôi có thể cung cấp cho bạn nhiều hơn chỉ là +1 :)
David Ferenczy Rogožan

Vâng, điều này thật tuyệt! Tôi đã thực hiện một lớp lót bằng cách sử dụng:$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

Sử dụng Measure-Command

Thí dụ

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

Các đường ống để Out-Hostcho phép bạn xem đầu ra của lệnh, được sử dụng theo cách khác Measure-Command.


Tôi nghĩ ý bạn là Measure-Command {<your command } | Out-Host - Out-Host nằm ngoài khối kịch bản
Peter McEvoy

1
@Peter - nó cần phải ở trong khối, nếu không, Lệnh-Lệnh sẽ tiêu thụ đầu ra trước khi nó đi đến bàn điều khiển.
Droj

1
Gotcha ... trong trường hợp đó, bạn thậm chí có thể không cần đường ống. Nó chỉ nên in kết quả, trừ khi bạn có nó được bọc trong một số khối khác ....
Droj

2
Out-Default có thể tốt hơn Out-Host vì tương thích với kịch bản không? jsnover.com/blog/2013/12/07/write-host-considered-harmful
MarcH

1
Vâng, tôi đã thử Out-Default và nó cũng hoạt động tốt trong một thiết bị đầu cuối, vậy tại sao không sử dụng Out-Default luôn? (Tôi đã không thử nó trong một kịch bản xin lỗi)
MarcH

18

Simples

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

sau đó có thể sử dụng như

time { .\some_command }

Bạn có thể muốn điều chỉnh đầu ra


1
Measure-Commandẩn đầu ra lệnh, vì vậy giải pháp này đôi khi tốt hơn.
codekaizen

Đây là một giải pháp tuyệt vời, tôn trọng đầu ra của lệnh. Bạn cũng có thể gọi nó mà không cần dấu ngoặc nhọn cho các lệnh đơn giản, ví dụ: "time ls", chính xác như bạn làm trong Unix.
Raúl Salinas-Monteagudo

5

Đây là một chức năng tôi đã viết hoạt động tương tự như timelệnh Unix :

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
    }
}

Nguồn: https://gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874


Câu hỏi là "Thời gian thực hiện lệnh trong PowerShell". Điều đó có liên quan gì đến việc định thời gian cho một quá trình sử dụng Unix?
Jean-Claude DeMars

5
Đó là hàm Powershell mà tôi đã viết, cho biết cách tự tính toán thời gian thực hiện thay vì sử dụng Measure-Commandhoặc một trong những cách khác mà bạn có thể thực hiện trong Powershell. Nếu bạn đọc câu hỏi ban đầu, anh ấy đã yêu cầu một cái gì đó hoạt động "như timelệnh trong Linux".
Bender lớn nhất

3

Sử dụng Đồng hồ bấm giờ và định dạng thời gian đã trôi qua:

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"
}

Mẫu sử dụng

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

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

-2

Chỉ cần một từ để rút ra kết luận (không chính xác) từ bất kỳ lệnh đo lường hiệu suất nào được đề cập trong các câu trả lời. Có một số cạm bẫy cần được xem xét ngoài việc tìm đến thời gian gọi trần của hàm hoặc lệnh (tùy chỉnh).

Sjoemelsoftware

'Sjoemelsoftware' đã bình chọn từ tiếng Hà Lan của năm 2015
Sjoemelen có nghĩa là gian lận, và từ sjoemelsoftware ra đời do vụ bê bối khí thải của Volkswagen. Định nghĩa chính thức là "phần mềm được sử dụng để ảnh hưởng đến kết quả kiểm tra".

Cá nhân, tôi nghĩ rằng " Sjoemelsoftware " không phải lúc nào cũng được cố tình tạo ra để gian lận kết quả kiểm tra mà có thể bắt nguồn từ việc cung cấp tình huống thực tế tương tự như các trường hợp thử nghiệm như dưới đây.

Như một ví dụ, bằng cách sử dụng lệnh đo lường hiệu suất niêm yết, Language Integrated Query (LINQ) (1) , thường có trình độ như các cách nhịn đói để có được một cái gì đó thực hiện và nó thường, nhưng chắc chắn không phải lúc nào! Bất kỳ ai đo tốc độ tăng của hệ số 40 trở lên so với các lệnh PowerShell gốc, có thể đo không chính xác hoặc đưa ra kết luận không chính xác.

Vấn đề là một số lớp .Net (như LINQ) sử dụng đánh giá lười biếng (còn được gọi là thực thi hoãn lại (2) ). Có nghĩa là khi gán một biểu thức cho một biến, nó gần như ngay lập tức được thực hiện nhưng thực tế nó chưa xử lý bất cứ điều gì!

Giả sử rằng bạn chấm nguồn. .\Dosomething.ps1 lệnh của bạn có PowerShell hoặc biểu thức Linq tinh vi hơn (để dễ giải thích, tôi đã nhúng trực tiếp các biểu thức vào 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

Kết quả có vẻ rõ ràng, lệnh Linq sau này nhanh hơn khoảng 40 lần so với lệnh PowerShell đầu tiên . Thật không may, nó không đơn giản ...

Hãy hiển thị kết quả:

PS C:\> $PowerShell

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

PS C:\> $Linq

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

Như mong đợi, kết quả là như nhau nhưng nếu bạn đã chú ý kỹ, bạn sẽ nhận thấy rằng phải mất nhiều thời gian hơn để hiển thị $Linqkết quả thì $PowerShellkết quả.
Chúng ta hãy đo cụ thể rằng chỉ cần lấy một thuộc tính của đối tượng kết quả:

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

Phải mất khoảng 90 yếu tố nữa để lấy một thuộc tính của $Linqđối tượng sau đó $PowerShellđối tượng và đó chỉ là một đối tượng!

Cũng lưu ý một cạm bẫy khác là nếu bạn làm lại, một số bước nhất định có thể xuất hiện nhanh hơn rất nhiều trước đó, điều này là do một số biểu thức đã được lưu trữ.

Tóm lại, nếu bạn muốn so sánh hiệu suất giữa hai chức năng, bạn sẽ cần triển khai chúng trong trường hợp đã sử dụng của mình, bắt đầu với phiên PowerShell mới và đưa ra kết luận về hiệu suất thực tế của giải pháp hoàn chỉnh.

(1) Để có thêm thông tin cơ bản và ví dụ về PowerShell và LINQ, tôi khuyên bạn nên sử dụng trang web tihis: PowerShell hiệu suất cao với LINQ
(2) Tôi nghĩ rằng có một sự khác biệt nhỏ giữa hai khái niệm như với đánh giá lười biếng , kết quả được tính khi cần được áp dụng cho thực hiện hoãn lại là kết quả được tính khi hệ thống không hoạt động


Mục đích của câu trả lời này là có thể giới thiệu cho mọi người một câu hỏi chung cho một quan niệm sai lầm chung về các lệnh thời gian trong PowerShell, như tôi vừa làm cho một câu hỏi lặp lại như: Câu hỏi Powershell - Tìm kiếm phương pháp nhanh nhất để lặp qua các đối tượng 500k tìm kiếm một trận đấu trong mảng đối tượng 500k khác
iRon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.