กำหนดเวลาการดำเนินการคำสั่งใน PowerShell


217

มีวิธีง่ายๆในการดำเนินการคำสั่งใน PowerShell เช่นคำสั่ง 'time' ใน Linux หรือไม่?
ฉันมากับสิ่งนี้:

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

แต่ฉันต้องการบางสิ่งที่ง่ายกว่าเช่น

time .\do_something.ps1

คำตอบ:


337

ได้.

Measure-Command { .\do_something.ps1 }

โปรดทราบว่าข้อเสียเล็กน้อยประการหนึ่งMeasure-Commandคือคุณไม่เห็นstdoutผลลัพธ์

[อัปเดตขอบคุณ @JasonMArcher] คุณสามารถแก้ไขได้โดยการไพพ์เอาต์พุตคำสั่งไปยัง commandlet บางตัวที่เขียนไปยังโฮสต์เช่นOut-Defaultนั้นจะกลายเป็น:

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

อีกวิธีในการดูผลลัพธ์ก็คือใช้Stopwatchคลาส. NET ดังนี้:

$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

13
$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 หรือวัดคำสั่งหรือเพียงแค่เปรียบเทียบสองได้รับวัน-vars ... (ผมหมายถึงสิ่งที่มีประสิทธิภาพมากขึ้นเพื่อให้ถาวรในสคริปต์?)
Hicsy

อาจรวมถึงส่วนสำคัญของความคิดเห็นของ JasonMArcher (ดังนั้นจึงเป็นที่ชัดเจนว่าสามารถใช้ในลักษณะที่ละเอียดกว่าสคริปต์ PowerShell ทั้งหมด)
Peter Mortensen

183

นอกจากนี้คุณยังจะได้รับคำสั่งสุดท้ายจากประวัติศาสตร์และลบของมันจากมันEndExecutionTimeStartExecutionTime

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

22
ลองใช้บางครั้ง: Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -descเพื่อดูรูปแบบการใช้ PowerShell ของคุณแบบรายชั่วโมง :-)
Keith Hill

18
+1 สำหรับความสามารถในการใช้สิ่งนี้เพื่อค้นหาว่ามีอะไรบางอย่างใช้เวลานานแม้ว่าคุณไม่ได้คาดหวังว่ามันจะใช้เวลานานเมื่อคุณเริ่มต้นดังนั้นคุณจึงไม่คิดที่จะห่อมันไว้ในเครื่องมือวัด
Chris Magnuson

3
PowerShell ยอดเยี่ยมในบางครั้ง
ConstantineK

ฉันหวังว่าฉันจะให้คุณมากกว่า +1 :)
David Ferenczy Rogožan

ใช่มันเยี่ยมมาก! ฉันใช้สายการบิน$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

ใช้ Measure-Command

ตัวอย่าง

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

ท่อที่จะช่วยให้คุณเห็นผลลัพธ์ของคำสั่งที่มีการบริโภคเป็นอย่างอื่นโดยOut-HostMeasure-Command


ฉันคิดว่าคุณหมายถึงMeasure-Command {<your command } | Out-Host - Out-Host อยู่นอกบล็อกสคริปต์
Peter McEvoy

1
@Peter - มันต้องอยู่ในบล็อกมิฉะนั้น Measure-Command จะใช้เอาต์พุตก่อนที่จะไปที่คอนโซล
Droj

1
Gotcha ... ในกรณีนั้นคุณอาจไม่ต้องการแม้แต่ท่อ มันก็ควรจะพิมพ์ผลเว้นแต่คุณจะมีมันห่อในบล็อกอื่น ๆ บางอย่าง ....
Droj

2
Out-Default อาจดีกว่า Out-Host เนื่องจากเข้ากันได้กับสคริปต์ jsnover.com/blog/2013/12/07/write-host-considered-harmful
มีนาคม

1
ฉันลอง Out-Default แล้วและมันก็ใช้ได้ดีในเทอร์มินัลด้วยดังนั้นทำไมไม่ใช้ Out-Default เสมอ? (ผมไม่ได้พยายามมันในสคริปต์ขออภัย)
มีนาคม

18

Simples

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

จากนั้นสามารถใช้เป็น

time { .\some_command }

คุณอาจต้องการปรับแต่งเอาท์พุท


1
Measure-Commandซ่อนเอาต์พุตคำสั่งดังนั้นโซลูชันนี้บางครั้งก็ดีกว่า
codekaizen

นี่เป็นทางออกที่ยอดเยี่ยมซึ่งเคารพเอาต์พุตของคำสั่ง คุณยังสามารถเรียกใช้มันโดยไม่ต้องใช้เครื่องหมายปีกกาสำหรับคำสั่งง่าย ๆ เช่น: "time ls" เหมือนกับที่คุณทำใน Unix
Raúl Salinas-Monteagudo

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 ได้ หากคุณอ่านคำถามต้นฉบับเขาจะถามถึงสิ่งที่ใช้ได้ "เหมือนtimeคำสั่งใน Linux"
Bender the Greatest

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

ข้อสรุปในรูปวาด (ไม่ถูกต้อง) จากคำสั่งการวัดประสิทธิภาพที่อ้างถึงในคำตอบ มีข้อผิดพลาดหลายประการที่ควรพิจารณานอกเหนือจากการมองไปที่เวลาร้องขอการเปลือยของฟังก์ชันหรือคำสั่ง (กำหนดเอง)

Sjoemelsoftware

'Sjoemelsoftware' โหวตให้ชาวดัตช์คำในปี 2015
Sjoemelenหมายถึงการโกงและคำว่า sjoemelsoftwareเกิดขึ้นเนื่องจากเรื่องอื้อฉาวการปล่อยมลพิษของโฟล์คสวาเกน คำจำกัดความอย่างเป็นทางการคือ "ซอฟต์แวร์ที่ใช้เพื่อมีอิทธิพลต่อผลการทดสอบ"

ส่วนตัวผมคิดว่า " Sjoemelsoftware " ไม่ได้ถูกสร้างขึ้นโดยเจตนาเพื่อโกงผลการทดสอบ แต่อาจเกิดจากการช่วยเหลือในสถานการณ์จริงที่คล้ายกับกรณีทดสอบดังที่แสดงด้านล่าง

เป็นตัวอย่างการใช้คำสั่งการวัดประสิทธิภาพในรายการภาษา Integrated Query (LINQ) (1)มักจะมีคุณสมบัติเป็นวิธี Fasted ที่จะได้รับสิ่งที่ทำและมันมักจะเป็น แต่ไม่แน่นอนเสมอ! ใครก็ตามที่วัดการเพิ่มความเร็วของปัจจัย 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ผล
Let 's โดยเฉพาะวัดที่โดยเพียงแค่การดึงคุณสมบัติของวัตถุผลไปนี้:

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) ผมคิดว่ามีความแตกต่างเล็ก ๆ น้อย ๆ ระหว่างสองแนวความคิดเช่นเดียวกับการประเมินผลขี้เกียจผลจะคำนวณได้เมื่อมีความจำเป็น apposed เป็นไปการดำเนินการที่ถูกเลื่อนออกไปเป็นผลลัพธ์จะถูกคำนวณเมื่อระบบไม่ได้ทำงาน


ความตั้งใจของคำตอบนี้คือสามารถอ้างอิงผู้คนถึงคำถามทั่วไปสำหรับความเข้าใจผิดทั่วไปเกี่ยวกับคำสั่งกำหนดเวลาใน PowerShell เนื่องจากฉันเพิ่งทำซ้ำคำถามเช่น: คำถาม Powershell - กำลังมองหาวิธีที่เร็วที่สุดในการวนวัตถุ 500k กำลังมองหาคู่ที่เหมาะสมในออบเจกต์อาร์เรย์อีก 500k
iRon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.