从入门到进阶:C#.NET Stopwatch 计时与性能测量全攻略

简介

Stopwatch.NET 提供的高精度计时器,位于 System.Diagnostics 命名空间。

底层依赖操作系统的高分辨率性能计数器(Performance Counter),当硬件支持时,其精度可达纳秒级;在不支持时退回到环境时钟(毫秒级)。

主要用途包括:

  • 性能测量(Benchmark

  • 代码片段耗时分析

  • 定时任务、超时检测

核心原理与特性

工作原理

Stopwatch 使用底层硬件计时器(通常是 CPU 的高分辨率性能计数器)提供纳秒级精度的时间测量:

graph LR A[应用程序] --> B[Stopwatch] B --> C[QueryPerformanceCounter API] C --> D[硬件计时器] D --> E[高精度时间测量]

关键特性

  • 高精度:最高可达纳秒级(取决于硬件)

  • 低开销:专门优化的计时实现

  • 独立计时:不受系统时间调整影响

  • 线程安全:可在多线程环境中安全使用

核心属性

属性 类型 描述
IsRunning bool 指示计时器是否正在运行
Elapsed TimeSpan 当前测量的总时间
ElapsedMilliseconds long 总毫秒数(整数)
ElapsedTicks long 计时器滴答计数
Frequency static long 每秒的计时器滴答数

核心 API

成员 说明
Start() 启动或继续计时(若已停止,则接着累加)。
Stop() 暂停计时,保留已累计时间。
Reset() 重置累计时间为零,但不改变运行状态(运行中依旧在计时)。
Restart() 等同于 Reset() + Start(),常用于重复测量。
IsRunning (bool) 当前是否在运行状态。
Elapsed 返回 TimeSpan 类型的累计运行时间。
ElapsedMilliseconds 累计运行总毫秒(取整)。
ElapsedTicks 累计运行计数器刻度数(与硬件计时器相关)。
静态属性 Frequency 性能计数器频率(每秒刻度数),用于将刻度转换为时间; IsHighResolution 表示是否为高分辨率计数器。

典型用法

基本测量

csharp 复制代码
var sw = Stopwatch.StartNew();    // 等同于 new Stopwatch(); sw.Start();
DoWork();
sw.Stop();
Console.WriteLine($"耗时:{sw.Elapsed.TotalMilliseconds} ms");

分段测量(Laps)

csharp 复制代码
var sw = new Stopwatch();
sw.Start();

// 第一段
DoStep1();
Console.WriteLine($"Step1: {sw.ElapsedMilliseconds} ms");

// 第二段
DoStep2();
Console.WriteLine($"Step2: {sw.ElapsedMilliseconds} ms");

// 重置累计,再测
sw.Restart();
DoOther();
Console.WriteLine($"Other: {sw.Elapsed.TotalMilliseconds} ms");

多次重复测量

csharp 复制代码
var sw = new Stopwatch();
for (int i = 0; i < 5; i++)
{
    sw.Restart();
    DoWork();
    Console.WriteLine($"Run {i}: {sw.ElapsedMilliseconds} ms");
}

精确时间计算

csharp 复制代码
// 纳秒级计算
long start = Stopwatch.GetTimestamp();
// 执行操作...
long end = Stopwatch.GetTimestamp();
double elapsedNs = (end - start) * 1_000_000_000 / (double)Stopwatch.Frequency;

进阶技巧

测量异步方法

csharp 复制代码
var sw = Stopwatch.StartNew();
await SomeAsyncOperation();
sw.Stop();
Console.WriteLine($"Async 耗时:{sw.ElapsedMilliseconds} ms");

嵌套测量

csharp 复制代码
var swTotal = Stopwatch.StartNew();
var swA = new Stopwatch(); swA.Start();
DoA(); swA.Stop();
var swB = Stopwatch.StartNew();
DoB(); swB.Stop();
swTotal.Stop();
Console.WriteLine($"A: {swA.Elapsed}  B: {swB.Elapsed}  Total: {swTotal.Elapsed}");

避免 GC 干扰

  • 对短时测量可先进行一次"热身"(预调用方法和计时器)以加载 JIT、内存分配等。

  • 可以在测量前后调用 GC.Collect(); GC.WaitForPendingFinalizers();,以减少 GC 的随机停顿对结果的影响。

性能测试框架

csharp 复制代码
public static TimeSpan MeasurePerformance(Action action, int iterations = 1000)
{
    // 预热
    action();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++)
    {
        action();
    }
    sw.Stop();
    
    return TimeSpan.FromTicks(sw.ElapsedTicks / iterations);
}

// 使用示例
var avgTime = MeasurePerformance(() => 
{
    // 测试的代码块
    var result = Enumerable.Range(0, 1000).Sum();
}, 10000);

Console.WriteLine($"平均执行时间: {avgTime.TotalMilliseconds:F6} ms");

高级应用场景

性能监控中间件

csharp 复制代码
public class PerformanceMonitorMiddleware
{
    private readonly RequestDelegate _next;
    
    public PerformanceMonitorMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task Invoke(HttpContext context)
    {
        var sw = Stopwatch.StartNew();
        
        await _next(context);
        
        sw.Stop();
        context.Response.Headers["X-Execution-Time"] = sw.ElapsedMilliseconds.ToString();
        
        // 记录到日志系统
        LogPerformance(context.Request.Path, sw.Elapsed);
    }
}

// 在Startup中注册
app.UseMiddleware<PerformanceMonitorMiddleware>();

算法复杂度分析

csharp 复制代码
public void AnalyzeAlgorithmComplexity()
{
    for (int n = 1000; n <= 1000000; n *= 10)
    {
        int[] data = Enumerable.Range(0, n).ToArray();
        
        var sw = Stopwatch.StartNew();
        Array.Sort(data); // 测试排序算法
        sw.Stop();
        
        Console.WriteLine($"n={n}, 时间={sw.ElapsedTicks} ticks");
    }
}
相关推荐
c#上位机10 小时前
halcon多个区域合并为1个区域—union1
c#·上位机·halcon·机器视觉
c#上位机11 小时前
halcon图像增强——图像取反
图像处理·算法·c#·halcon
zwm26988881511 小时前
悦龙台 监控掉线问题
c#
c#上位机11 小时前
halcon图像去噪—导向滤波
图像处理·人工智能·计算机视觉·c#·halcon
切糕师学AI12 小时前
Z.EntityFramework.Extensions.Core 如何批量删除数据?
c#
CHANG_THE_WORLD12 小时前
Python 中的循环结构详解
开发语言·python·c#
c#上位机13 小时前
halcon获取多个独立连通域—connection
图像处理·c#·halcon
烛阴18 小时前
代码的“病历本”:深入解读C#常见异常
前端·c#
努力小周19 小时前
基于STM32的智能台灯系统设计与实现
stm32·单片机·嵌入式硬件·c#·毕业设计·毕设·javaee
arron889919 小时前
C# 项目源码进行全面的技术架构和调用逻辑分析。以下是系统性的技术方案
开发语言·架构·c#