DateTime.Now bir işlevin performansını ölçmenin en iyi yolu mu?


474

Bir darboğaz bulmam ve zamanı olabildiğince doğru bir şekilde ölçmem gerekiyor.

Aşağıdaki kod snippet'i, performansı ölçmenin en iyi yolu mu?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

Bu arada, hızlı ve kirli bir şey aramıyorsanız performans sayaçları kullanılabilir.
Jonathan C Dickinson

1
Daha fazla hassasiyete ihtiyacınız varsa Kronometre.GetTimestamp kullanın, aksi takdirde cevap iyidir.
6:11 da dbasnett

@dbasnett Bir cevapta daha ayrıntılı bilgi verebilir misiniz?
David Basarab

Yukarıdaki örnekte başlangıç ​​ve bitiş zamanını uzun olarak değiştirin ve DateTime.Now yerine Kronometre.GetTimestamp atayın. Alınan zaman (başlangıç) /Stopwatch.Frekans.
dbasnett

Yanıtlar:


649

Hayır değil. Kronometreyi Kullan (in System.Diagnostics)

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Kronometre otomatik olarak yüksek hassasiyetli zamanlayıcıların olup olmadığını kontrol eder.

Zaman dilimleri, DST ve benzerleri ile yapılması gereken işlerden DateTime.Nowgenellikle biraz daha yavaş olduğunu DateTime.UtcNowbelirtmek gerekir .

DateTime.UtcNow tipik olarak 15 ms'lik bir çözünürlüğe sahiptir. Mükemmel bir özet için John Chapman'ınDateTime.Now hassasiyet hakkındaki blog yayınına bakın .

İlginç bilgiler: DateTime.UtcNowDonanımınız yüksek frekanslı bir sayacı desteklemiyorsa kronometre yeniden çalışır . Sen Kronometre statik alan bakarak yüksek hassasiyet elde etmek donanım kullanır olmadığını kontrol edebilirsiniz Stopwatch.IsHighResolution .


3
Bir PerformWork () yerleştiririm; "ısınma" için Kronometreden önce.
DiVan

2
Ayrıca PerformWork(), çok kısaysanız, tekrar tekrar arayabileceğiniz ve arama grubunun ortalamasını hesaplayabileceğiniz konusunda öneri eklemeniz gerekir . Ayrıca, Stopwatchzamanlama ölçümlerinizi çamurlaştıracak bir flaş efektinden kaçınmak için , başlatmak / durdurmak yerine tüm çağrı grubunu zamanlayın.
devgeezer

1
Kronometre çok çekirdekli için güvenli değildir. Bkz. Stackoverflow.com/questions/6664538/… ve stackoverflow.com/questions/1149485/…
Pavel Savara

1
sw.ElapsedMilliseconds; ayrıca
Flappy

2
@Pavel, açıkçası, Windows 7 ve Windows 8 çalıştıran modern çok çekirdekli işlemcilerde Kronometre Microsoft tarafından en iyi çözüm (düşük ek yük ve yüksek hassasiyet) olarak önerilmektedir. msdn.microsoft.com/en-us/library/windows/ masaüstü /…
Ron

91

Hızlı ve kirli bir şey istiyorsanız, daha fazla hassasiyet için Kronometre kullanmanızı öneririm.

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

Alternatif olarak, biraz daha sofistike bir şeye ihtiyacınız varsa, muhtemelen ANTS gibi bir 3. taraf profil oluşturucu kullanmayı düşünmelisiniz .


56

Bu makale , her şeyden önce üç alternatifi karşılaştırmanız gerektiğini söylüyor Stopwatch, DateTime.NowAND DateTime.UtcNow.

Ayrıca, bazı durumlarda (performans sayacı mevcut olmadığında) Kronometre'nin DateTime.UtcNow + ekstra işlem kullandığını gösterir. Bu nedenle, bu durumda DateTime.UtcNow'un en iyi seçenek olduğu açıktır (çünkü diğer kullanımı + bazı işlemler)

Ancak, ortaya çıktığı gibi, sayaç neredeyse her zaman var - bkz. Yüksek çözünürlüklü performans sayacı ve .NET Kronometre ile ilgili varlığı hakkında açıklama? .

İşte bir performans grafiği. UtcNow'un düşük performans maliyetinin alternatiflere kıyasla ne kadar düşük olduğuna dikkat edin:

Resim açıklamasını buraya girin

X ekseni örnek veri boyutudur ve Y ekseni örneğin göreli süresidir.

Bir şey Stopwatchdaha iyi, daha yüksek çözünürlük zaman ölçümleri sağlamasıdır. Bir diğeri daha çok OO doğası. Ancak, etrafında bir OO sarmalayıcısı oluşturmak UtcNowzor olamaz.


İlk bağlantı kopmuş gibi görünüyor.
Peter Mortensen

1
yep kırıldı .. zaman makinesi sanırım bunu gösterebilir. Neden bu üçü düzenlediğinize inanmıyorum.
Valentin Kuzub

18

Kıyaslama kodunuzu bir yardımcı program sınıfına / yönteme aktarmak için kullanışlıdır. StopWatchSınıf olmak gerekmez Disposedveya Stoppedhata. Yani, en basit kod için zaman bazı eylem olduğu

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

Örnek arama kodu

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

İşte uzantı yöntemi sürümü

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

Ve örnek arama kodu

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat(“Did action in {0} ms.”, time);
}

1
Daha iyi ayrıntı düzeyi ne olacak? Birçok şey birden fazla ms'de olur.
Henrik

Elapsed özelliğini döndürün, bu bir TimeSpan. Size sadece kalıbı gösteriyorum. Uygularken eğlenin.
Anthony Mastrean

Elapsed.TotalMillisecondsDaha yüksek hassasiyet için geri dönün . Bu soruya da bakınız stackoverflow.com/questions/8894425/…
nawfal

16

Kronometre işlevselliği daha iyi (yüksek hassasiyet) olur. Ayrıca, sadece popüler profilerlerden birini indirmenizi de tavsiye ederim ( DotTrace ve ANTS en çok kullandıklarım ... DotTrace için ücretsiz deneme sürümü tamamen işlevsel ve diğerleri gibi nag yok).


13

System.Diagnostics.Stopwatch sınıfını kullanın.

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

11

Aynen Kronometre, çok daha iyi.

Performans ölçümü ile ilgili olarak, "// Bazı Yürütme Sürecinizin" çok kısa bir süreç olup olmadığını da kontrol etmelisiniz.

Ayrıca, "// Bazı Yürütme Sürecinizin" ilk çalıştırmasının sonraki çalıştırmalardan çok daha yavaş olabileceğini unutmayın.

Genellikle bir yöntemi bir döngüde 1000 kez veya 1000000 kez çalıştırarak test ederim ve bir kez çalıştırmaktan çok daha doğru veriler elde ederim.


9

Bunların hepsi zamanı ölçmenin harika yollarıdır, ancak bu darboğazları bulmanın sadece dolaylı bir yoludur.

Bir iş parçacığında bir darboğaz bulmanın en doğrudan yolu, onu çalıştırmaktır ve sizi bekleten her şeyi yaparken, bir duraklama veya kesme tuşu ile durdurun. Bunu birkaç kez yapın. Darboğazınız% X zaman alırsa,% X her anlık görüntüdeki eylemde yakalama olasılığınızdır.

İşte nasıl ve neden çalıştığına dair daha eksiksiz bir açıklama


7

@ Sean Chambers

FYI, .NET Timer sınıfı tanılama amaçlı değildir, önceden ayarlanmış bir aralıkta ( MSDN'den ) olaylar oluşturur :

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

Yani bu gerçekten bir şeyin ne kadar sürdüğünü bilmenize yardımcı olmaz, sadece belirli bir süre geçti.

Zamanlayıcı da System.Windows.Forms'da bir kontrol olarak gösterilir ... VS05 / VS08'deki tasarımcı araç kutunuzda bulabilirsiniz


6

Doğru yol budur:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

Daha fazla bilgi için doğru performans sayacı almak amacıyla DataTime yerine Kronometre'yi kullanın .


6

Visual Studio Team System , bu soruna yardımcı olabilecek bazı özelliklere sahiptir. Temelde, bir stres veya yük testinin parçası olarak yazılımınıza karşı çalıştırmak için birim testleri yazabilir ve bunları farklı senaryolarda karıştırabilirsiniz. Bu, uygulamalarınızın performansını en fazla etkileyen kod alanlarını belirlemenize yardımcı olabilir.

Microsoft'un Desenler ve Uygulamaları grubunun Visual Studio Team Sistem Performansı Test Kılavuzu'nda bazı rehberleri vardır .



5

Bu yeterince profesyonel değil:

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Daha güvenilir bir versiyon:

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);

Gerçek kodumda, yönetilen yığını bilinen bir duruma değiştirmek için GC.Collect çağrısı ekleyeceğim ve farklı kod aralıklarının ETW profilinde kolayca ayrılabilmesi için Uyku çağrısı ekleyeceğim.


4

Ben bu tür bir performans kontrolü çok az yaptım (sadece "bu yavaş, daha hızlı olun" düşünmek eğilimindedir) bu yüzden hemen hemen her zaman bu gitti.

Google, performans kontrolü için birçok kaynak / makale ortaya koymaktadır.

Birçoğu performans bilgisi almak için pinvoke kullandığından bahsediyor. İncelediğim materyallerin çoğu sadece perfmon kullanarak bahsetti.

Düzenle:

StopWatch görüşmelerini gördüm .. Güzel! Bir şey öğrendim :)

Bu iyi bir makale gibi görünüyor


4

Programlarımda kullandığım yol, burada gösterildiği gibi StopWatch sınıfını kullanmaktır.

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;
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.