DateTime. Cách tốt nhất để đo hiệu suất của chức năng?


474

Tôi cần tìm một nút cổ chai và cần đo chính xác nhất có thể thời gian.

Đoạn mã sau có phải là cách tốt nhất để đo hiệu suất không?

DateTime startTime = DateTime.Now;

// Some execution process

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

Nhân tiện, nếu bạn không tìm kiếm thứ gì đó nhanh chóng và bộ đếm hiệu suất bẩn có thể được sử dụng.
Jonathan C Dickinson

1
Nếu bạn cần độ chính xác cao hơn, hãy sử dụng Stopwatch.GetTimestamp, nếu không thì câu trả lời là tốt.
dbasnett

@dbasnett Bạn có thể đi vào chi tiết hơn trong câu trả lời không?
David Basarab

Trong ví dụ trên, thay đổi bắt đầu và thời gian kết thúc thành dài và gán Stopwatch.GetTimestamp cho chúng thay vì DateTime.Now. Thời gian thực hiện là (kết thúc bắt đầu) /Stopwatch.Frequency.
dbasnett

Câu trả lời:


649

Không, không phải vậy. Sử dụng Đồng hồ bấm giờ (trong System.Diagnostics)

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

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

Đồng hồ bấm giờ tự động kiểm tra sự tồn tại của bộ hẹn giờ có độ chính xác cao.

Điều đáng nói là DateTime.Nowthường chậm hơn một chút so DateTime.UtcNowvới công việc phải làm với múi giờ, DST và như vậy.

DateTime.UtcNow thường có độ phân giải 15 ms. Xem bài viết trên blog của John Chapman về DateTime.Nowđộ chính xác để có một bản tóm tắt tuyệt vời.

Câu đố thú vị: Đồng hồ bấm giờ rơi lại DateTime.UtcNownếu phần cứng của bạn không hỗ trợ bộ đếm tần số cao. Bạn có thể kiểm tra xem Đồng hồ bấm giờ có sử dụng phần cứng để đạt được độ chính xác cao hay không bằng cách xem trường tĩnh Stopwatch.IsHighResolution .


3
Tôi sẽ đặt một PerformanceWork (); trước khi bấm giờ để "làm nóng".
DiVan

2
Cũng phải thêm khuyến nghị rằng nếu bạn PerformWork()rất ngắn mà bạn có thể gọi nó nhiều lần và tính trung bình của lô cuộc gọi. Ngoài ra, thời gian cho toàn bộ một loạt các cuộc gọi thay vì bắt đầu / dừng cuộc gọi của bạn Stopwatchđể tránh hiệu ứng nhấp nháy sẽ làm vẩn đục các phép đo thời gian của bạn.
devgeezer

1
Đồng hồ bấm giờ không phải là chủ đề an toàn trên đa lõi. Xem stackoverflow.com/questions/6664538/...stackoverflow.com/questions/1149485/...
Pavel Savara

1
sw.ElapsedMilliseconds; cũng có thể
Flappy

2
@Pavel, rõ ràng, Đồng hồ bấm giờ được Microsoft khuyên dùng là giải pháp tốt nhất (chi phí thấp và độ chính xác cao) trên các bộ xử lý đa lõi hiện đại đang chạy Windows 7 và Windows 8. msdn.microsoft.com/en-us/l Library /
Ron

91

Nếu bạn muốn thứ gì đó nhanh và bẩn, tôi khuyên bạn nên sử dụng Đồng hồ bấm giờ để có độ chính xác cao hơn.

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

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

Ngoài ra, nếu bạn cần một cái gì đó tinh vi hơn một chút, có lẽ bạn nên xem xét sử dụng trình lược tả bên thứ 3 như ANTS .


56

Bài viết này nói rằng trước hết bạn cần so sánh ba lựa chọn thay thế Stopwatch, DateTime.NowDateTime.UtcNow.

Nó cũng cho thấy rằng trong một số trường hợp (khi bộ đếm hiệu suất không tồn tại) Đồng hồ bấm giờ đang sử dụng DateTime.UtcNow + một số xử lý bổ sung. Do đó, rõ ràng là trong trường hợp đó DateTime.UtcNow là tùy chọn tốt nhất (vì người khác sử dụng nó + một số xử lý)

Tuy nhiên, khi nó bật ra, bộ đếm hầu như luôn tồn tại - xem Giải thích về bộ đếm hiệu suất độ phân giải cao và sự tồn tại của nó liên quan đến Đồng hồ bấm giờ .NET? .

Đây là một biểu đồ hiệu suất. Thông báo chi phí thấp hiệu suất UtcNow đã so với lựa chọn thay thế như thế nào:

Nhập mô tả hình ảnh ở đây

Trục X là kích thước dữ liệu mẫu và trục Y là thời gian tương đối của ví dụ.

Một điều Stopwatchtốt hơn là nó cung cấp các phép đo thời gian độ phân giải cao hơn. Khác là hơn OO bản chất của nó. Tuy nhiên, việc tạo ra một OO wrapper xung quanh UtcNowkhông thể cứng.


Các liên kết đầu tiên dường như bị phá vỡ.
Peter Mortensen

1
trở thành bị phá vỡ vâng .. cỗ máy thời gian có thể hiển thị nó tôi sẽ đoán. Btw tại sao bạn chỉnh sửa "ba", tôi không cần ở đây.
Valentin Kuzub

18

Nó rất hữu ích để đẩy mã điểm chuẩn của bạn thành một lớp tiện ích / phương pháp. Các StopWatchlớp không cần phải Disposedhoặc Stoppedvề lỗi. Vì vậy, mã đơn giản nhất để thực hiện một số hành động

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

Mã gọi mẫu

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

Đây là phiên bản phương thức mở rộng

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

Và mã gọi mẫu

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

1
Điều gì về độ chi tiết tốt hơn? Nhiều điều xảy ra trong ít hơn một ms.
Henrik

Trả lại tài sản đã qua rồi, đó là một TimeSpan. Tôi chỉ cho bạn thấy mô hình. Hãy vui vẻ thực hiện nó.
Anthony Mastrean

Trả lại Elapsed.TotalMillisecondscho độ chính xác cao hơn. Xem câu hỏi này quá stackoverflow.com/questions/8894425/ từ
nawfal

16

Các đồng hồ bấm giờ chức năng sẽ tốt hơn (độ chính xác cao hơn). Tuy nhiên, tôi cũng khuyên bạn chỉ nên tải xuống một trong những trình biên dịch phổ biến ( DotTraceANTS là những trình tôi đã sử dụng nhiều nhất ... bản dùng thử miễn phí cho DotTrace có đầy đủ chức năng và không cằn nhằn như một số trình khác).


13

Sử dụng lớp System.Diagnostics.Stopwatch.

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

// Do some code.

sw.Stop();

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

11

Đồng hồ bấm giờ Ditto, nó là cách tốt hơn.

Về đo lường hiệu suất, bạn cũng nên kiểm tra xem "// Một số quy trình thực hiện" của bạn có phải là một quy trình rất ngắn hay không.

Cũng nên nhớ rằng lần chạy đầu tiên của "// Một số quy trình thực hiện" có thể chậm hơn các lần chạy tiếp theo.

Tôi thường kiểm tra một phương thức bằng cách chạy nó 1000 lần hoặc 1000000 lần trong một vòng lặp và tôi nhận được dữ liệu chính xác hơn nhiều so với chạy nó một lần.


9

Đây đều là những cách tuyệt vời để đo thời gian, nhưng đó chỉ là một cách rất gián tiếp để tìm ra nút cổ chai.

Cách trực tiếp nhất để tìm một nút thắt trong một luồng là để nó chạy, và trong khi nó đang làm bất cứ điều gì khiến bạn chờ đợi, hãy dừng nó bằng một phím tạm dừng hoặc ngắt. Làm điều này nhiều lần. Nếu nút cổ chai của bạn mất X% thời gian, X% là xác suất bạn sẽ nắm bắt được trong hành động trên mỗi ảnh chụp.

Đây là một lời giải thích đầy đủ hơn về cách thức và lý do tại sao nó hoạt động


7

@ Sean Chambers

FYI, lớp .NET Timer không dành cho chẩn đoán, nó tạo ra các sự kiện theo một khoảng thời gian định sẵn, như thế này (từ MSDN ):

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

Vì vậy, điều này thực sự không giúp bạn biết được một cái gì đó đã mất bao lâu, chỉ là một khoảng thời gian nhất định đã trôi qua.

Các bộ đếm thời gian cũng được tiếp xúc như một điều khiển trong System.Windows.Forms ... bạn có thể tìm thấy nó trong hộp công cụ thiết kế của bạn trong VS05 / VS08


6

Đây là cách chính xác:

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

Để biết thêm thông tin, hãy sử dụng Đồng hồ bấm giờ thay vì DataTime để có bộ đếm hiệu suất chính xác .


6

Visual Studio Team System có một số tính năng có thể giúp giải quyết vấn đề này. Về cơ bản, bạn có thể viết các bài kiểm tra đơn vị và trộn chúng trong các tình huống khác nhau để chạy với phần mềm của bạn như là một phần của bài kiểm tra căng thẳng hoặc tải. Điều này có thể giúp xác định các khu vực mã ảnh hưởng đến hiệu suất ứng dụng của bạn nhiều nhất.

Nhóm Thực hành và Mô hình của Microsoft có một số hướng dẫn trong Hướng dẫn Kiểm tra Hiệu suất Hệ thống của Nhóm Visual Studio .


5

Tôi chỉ tìm thấy một bài đăng trong blog của Vance Morrison về một lớp CodeTimer ông viết rằng làm cho sử dụng StopWatchdễ dàng hơn và làm một số công cụ gọn gàng trên mặt.


5

Điều này không đủ chuyên nghiệp:

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

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

Một phiên bản đáng tin cậy hơn là:

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);

Trong mã thực của tôi, tôi sẽ thêm lệnh gọi GC.Collect để thay đổi heap được quản lý sang trạng thái đã biết và thêm lệnh gọi Ngủ để các khoảng mã khác nhau có thể dễ dàng tách ra trong cấu hình ETW.


4

Tôi đã thực hiện rất ít việc kiểm tra hiệu suất này (tôi có xu hướng chỉ nghĩ rằng "việc này chậm, làm cho nó nhanh hơn") vì vậy tôi đã đi khá nhiều với việc này.

Một google không tiết lộ rất nhiều tài nguyên / bài báo để kiểm tra hiệu suất.

Nhiều người đề cập đến việc sử dụng pinvoke để có được thông tin hiệu suất. Rất nhiều tài liệu tôi nghiên cứu chỉ thực sự đề cập đến bằng cách sử dụng perfmon ..

Biên tập:

Nhìn thấy các cuộc nói chuyện của StopWatch .. Tốt đẹp! Tôi đã học được điều gì đó :)

Đây có vẻ là một bài viết tốt


4

Cách tôi sử dụng trong các chương trình của mình là sử dụng lớp StopWatch như được hiển thị ở đây.

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


// Critical lines of code

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