PowerShell'de bir komutun yürütülmesini zamanlama


217

Linux'taki 'zaman' komutu gibi PowerShell'de bir komutun yürütülmesini zamanlamanın basit bir yolu var mı?
Ben bununla geldim:

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

Ama daha basit bir şey istiyorum

time .\do_something.ps1

Yanıtlar:


337

Evet.

Measure-Command { .\do_something.ps1 }

Küçük bir dezavantajı çıktı görmemeniz Measure-Commandolduğunu unutmayın stdout.

[@JasonMArcher sayesinde güncelleme] Komut çıktısını ana bilgisayara yazan bir komut dosyasına borulandırarak düzeltebilirsiniz, örneğin Out-Default:

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

Çıktıyı görmenin başka bir yolu, .NET Stopwatchsınıfını şu şekilde kullanmak olacaktır :

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

114
Bunun gibi çıktıları da görebilirsiniz, Measure-Command {ps | Dışı Varsayılan}. Ya da doğrudan ana bilgisayara yazılan ve yararlı olabilecek veya olmayabilecek herhangi bir şey.
JasonMArcher

18
Bu çözümü aldım ve başka birine faydalı olabilecek bir işlev yazdım. gist.github.com/2206444 - Örnek: time { ping -n 1 google.com } -Samples 10komut 10sürelerini çalıştırır ve alınan ortalama, minimum ve maksimum süreyi döndürür. -SilentSTDOUT'u yutmak için ekleyebilirsiniz .
joshuapoehls

13
Benim tercihim Measure-Command sonucunu gibi bir değişkene atamaktır $t = Measure-Command {<<your command or code block>>}. Deneyin ve sonra yazın $tsonuçlarınızı ve benzeri erişimi olan tüm özellikleri görmek için istemi de $t.Milliseconds, $t.TotalSecondsörneğin, vb Sonra istediğimizi çıktı yazabilirWrite-Host That command took $t.TotalSeconds to complete.
Baodad

ne kullanmak daha hızlı? net.stopwatch, ölçü-komuta ya da sadece iki olsun tarih ... (? Acımasız bir komut kalıcı tutmak daha verimli ne) vars karşılaştıran
Hicsy

Belki JasonMArcher'ın yorumunun özünü de ekleyin (bu nedenle, tüm bir PowerShell betiğinden daha ince bir şekilde kullanılabileceği açıktır)?
Peter Mortensen

183

Ayrıca geçmişten son komutu almak ve amaçlarını çıkarabilirsiniz EndExecutionTimeonun dan StartExecutionTime.

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

22
Bunu bir süre deneyin: Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -descPowerShell kullanım düzeninizi günün saatine göre görmek için. :-)
Keith Hill

18
Başlamak için uzun zaman almasını beklemediğinizde bile bir şeyin ne kadar sürdüğünü öğrenmek için bunu kullanabilmek için +1'yi kullanın, böylece Ölçüm-Komutuna sarmayı düşünmediniz.
Chris Magnuson

3
Powershell bazen harika.
ConstantineK

Keşke sana sadece +1'den fazlasını
verebilsem

Evet, bu harika! Şunu kullanarak bir astar yaptım:$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

kullanım Measure-Command

Misal

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

Boru Out-Host, aksi takdirde tarafından tüketilen komutun çıktısını görmenizi sağlar Measure-Command.


Demek istediğim Measure-Command {<your command } | Out-Host - Out-Host senaryo bloğunun dışında
Peter McEvoy

1
@Peter - bloğun içinde olması gerekir, aksi takdirde Measure-Command konsola gitmeden önce çıkışı tüketir.
Droj

1
Yakaladım ... bu durumda boruya bile ihtiyacınız olmayabilir. Başka bir bloğa
sarılmadıkça

2
Out-Default, komut dosyası oluşturma ile uyumlu olduğu için Out-Host'dan daha iyi olabilir mi? jsnover.com/blog/2013/12/07/write-host-considered-harmful
MarcH

1
Peki Out-Default denedim ve bir terminalde de gayet iyi çalışıyor, bu yüzden neden Out-Default kullanmıyorsunuz? (Üzgünüm bir senaryoda denemedim)
MarcH

18

simples

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

sonra kullanabilirsiniz

time { .\some_command }

Çıktıyı değiştirmek isteyebilirsiniz


1
Measure-Commandkomut çıkışını gizler, bu nedenle bu çözüm bazen daha iyidir.
codekaizen

Bu, komutun çıktısına saygı duyan harika bir çözümdür. Basit komutlar için kıvırcık parantez olmadan da çağırabilirsiniz, örneğin: "time ls", tıpkı Unix'te yaptığınız gibi.
Raúl Salinas-Monteagudo

5

Unix timekomutuna benzer şekilde yazdığım bir fonksiyon :

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

Kaynak: https://gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874


Soru "Bir komutun PowerShell'de yürütülmesini zamanlama" idi. Bunun Unix kullanarak bir işlem zamanlamasıyla ne ilgisi var?
Jean-Claude DeMars

5
Yazdığım bir Powershell işlevi, kullanmak yerine yürütme süresini nasıl hesaplayacağınızı Measure-Commandveya Powershell'de yürütmeyi zamanlamanın çeşitli yollarından birini gösterir. Orijinal soruyu okursanız, " timeLinux'taki komut gibi" çalışan bir şey istedi .
En Büyük Bender'ı

3

Kronometreyi kullanma ve geçen süreyi biçimlendirme:

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

Kullanım Örnekleri

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

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

-2

Yanıtlarda atıfta bulunulan performans ölçüm komutlarının herhangi birinden çizim (yanlış) sonuçları. Bir (özel) fonksiyonun veya komutun çıplak çağırma süresine bakmanın yanı sıra dikkate alınması gereken birtakım tuzaklar vardır.

Sjoemelsoftware

'Sjoemelsoftware' 2015 yılının Hollandaca kelimesini
oyladı Sjoemelen hile yapmak anlamına geliyor ve sjoemelsoftware kelimesiVolkswagen emisyon skandalı nedeniyle ortaya çıktı. Resmi tanım "test sonuçlarını etkilemek için kullanılan yazılım" dır.

Şahsen, " Sjoemelsoftware " in test sonuçlarını kopyalamak için her zaman kasıtlı olarak yaratılmadığını, ancak aşağıda gösterildiği gibi test senaryolarına benzer pratik durumlardan kaynaklanabileceğini düşünüyorum.

Bir örnek olarak, listelenen performans ölçüm komutları kullanarak, Language Integrated Query (LINQ) (1) , sıklıkla nitelikli ama kesinlikle her zaman değil, bir şeyler halletmek için oruç tuttuklarını şekilde ve genellikle! Faktör 40 veya daha fazla bir hız artışını ölçen herkesYerel PowerShell komutlarına kıyasla , muhtemelen yanlış ölçüm yapar veya yanlış bir sonuç çıkarır.

Mesele şu ki, tembel bir değerlendirme ( ertelenmiş yürütme olarak da adlandırılır ) kullanan bazı .Net sınıfları (LINQ gibi ) ). Bu, bir değişkene bir ifade atarken neredeyse anında yapıldığı anlaşılır, ancak aslında henüz hiçbir şey işlemedi!

Eğer farz edelim nokta kaynak için . .\Dosomething.ps1ya bir PowerShell veya daha sofistike Linq ifade var komutu (açıklama kolaylığı için, doğrudan doğrudan ifadeleri gömülü olan 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

Sonuç açık görünüyor, sonraki Linq komutu ilk PowerShell komutundan yaklaşık 40 kat daha hızlı . Ne yazık ki, o kadar basit değil ...

Sonuçları görüntüleyelim:

PS C:\> $PowerShell

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

PS C:\> $Linq

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

Beklendiği gibi, sonuçlar aynıdır, ancak yakından dikkat ettiyseniz, $Linqsonuçların ve sonuçların görüntülenmesinin çok daha uzun sürdüğünü fark etmiş olacaksınız $PowerShell.
En spesifik olarak ölçmek edelim o sadece sonuçlandı nesnenin bir özelliğini alarak:

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

Nesnenin bir nesneden sonra nesnenin bir özelliğini almak yaklaşık 90 kat daha uzun sürdü ve bu sadece tek bir nesneydi!$Linq$PowerShell

Ayrıca, tekrar yaparsanız, belirli adımların öncekinden çok daha hızlı görünebileceği başka bir tuzağa dikkat edin, bunun nedeni bazı ifadelerin önbelleğe alınmasıdır.

Sonuç olarak, iki işlev arasındaki performansı karşılaştırmak istiyorsanız, bunları kullanılan durumunuza uygulamanız, yeni bir PowerShell oturumuyla başlamanız ve sonucunuzu tam çözümün gerçek performansına dayandırmanız gerekir.

(1) PowerShell ve LINQ hakkında daha fazla arka plan ve örnekler için, şu siteyi tavsiye ederim: LINQ ile Yüksek Performanslı PowerShell
(2) Tembel değerlendirme ile sonuç gerektiği gibi hesaplandığında , iki kavram arasında küçük bir fark olduğunu düşünüyorum . ertelenmiş yürütme sonucu, sistem boştayken hesaplanır


Bu cevabın amacı insanları zamanlama komutlarıyla ilgili genel bir yanlış anlama için ortak bir soruya yönlendirebilmektir. : Sadece gibi tekrarlayan bir soru için yaptığı gibi, PowerShell 500k nesneler aracılığıyla döngü için en hızlı yöntem için Looking - Powershell soruya başka bir 500k nesne dizisinde bir eşleşme arıyor
iRon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.