0

0

c# Stopwatch.GetTimestamp() 和高精度性能测量

畫卷琴夢

畫卷琴夢

发布时间:2026-01-02 11:17:02

|

818人浏览过

|

来源于php中文网

原创

Stopwatch.GetTimestamp() 返回的是底层硬件计时器的滴答数(ticks),单位为未公开起始点以来的整数计数值,需配合 Stopwatch.Frequency 换算为秒或纳秒,不可直接当作时间单位使用。

c# stopwatch.gettimestamp() 和高精度性能测量

Stopwatch.GetTimestamp() 返回的是什么单位?

Stopwatch.GetTimestamp() 返回的是一个 long 类型的整数,代表自某个未公开起始点以来的「计时器滴答数(ticks)」,不是毫秒、纳秒,也不是 .NET 的 DateTime 那种 100 纳秒单位。它的实际物理单位取决于底层硬件计时器(通常是 CPU 的高精度性能计数器,如 TSC),所以**不能直接当时间用**,必须配合 Stopwatch.Frequency 换算。

常见错误是把它当成纳秒或直接减完就除 1000 当毫秒——这在大多数现代 Windows 机器上会严重偏大(因为 TSC 频率常是 2–4 GHz,即每秒 20–40 亿次滴答)。

  • Stopwatch.Frequency 是每秒多少次 GetTimestamp() 滴答,例如 3_200_000_000
  • 两次调用差值 delta 除以 Frequency 才是秒:(double)delta / Stopwatch.Frequency
  • 想转纳秒?乘 1_000_000_000(delta * 1_000_000_000) / Stopwatch.Frequency(注意整数溢出风险)

为什么不用 Stopwatch.ElapsedMilliseconds 测微秒级开销?

Stopwatch.ElapsedMilliseconds 只返回 long,精度固定为毫秒,会直接截断小数部分;而 Stopwatch.Elapsed.TotalMilliseconds 虽是 double,但内部仍基于相同滴答计数,只是做了浮点换算——问题不在它“不准”,而在**默认构造和测量方式容易掩盖抖动**。

真正影响微秒级测量可靠性的,是测量本身引入的噪声:JIT 预热不足、GC 干扰、线程调度、CPU 频率缩放(Intel SpeedStep / AMD Cool'n'Quiet)、甚至测量代码自身执行时间。比如测一个空方法,GetTimestamp() 调用本身的开销可能就占几十纳秒。

  • 务必用 Stopwatch.IsHighResolution 确认底层用了 HPET 或 TSC,否则 fallback 到 QueryPerformanceCounter 甚至 GetTickCount64,精度可能只有 10–15ms
  • 单次测量毫无意义;至少跑几百到几万次,取中位数或 p95,再减去空循环基线(control baseline)
  • Thread.Sleep(0)GC.Collect() 强制干扰后重测,观察方差是否突增——这是判断测量是否被系统干扰的快速信号

如何安全地用 GetTimestamp() 做低开销高频采样?

如果你在写高性能网络库、实时音频处理或游戏逻辑帧统计,需要每帧/每次回调都打点,Stopwatch.Start()/Stop() 的方法调用开销(尤其是检查状态、读寄存器)可能成为瓶颈。GetTimestamp() 是静态、无状态、无锁的,适合内联采样。

Magic AI Avatars
Magic AI Avatars

神奇的AI头像,获得200多个由AI制作的自定义头像。

下载
private static readonly long _frequency = Stopwatch.Frequency;
private long _startTick;
<p>public void BeginSample() => _startTick = Stopwatch.GetTimestamp();</p><p>public double EndSampleInMs()
{
long end = Stopwatch.GetTimestamp();
long delta = end - _startTick;
return (double)delta * 1000.0 / _frequency; // 毫秒,保留小数
}

注意:不要在多线程共享同一个 _startTick 字段;也不要跨线程复用同一实例做 Begin/End —— GetTimestamp() 是线程安全的,但你的字段不是。

  • 避免在 try/finally 中调用 EndSampleInMs(),异常路径可能让 _startTick 滞留成脏值
  • 如果需长期运行的持续采样(如每毫秒打一次点),考虑用环形缓冲区存原始 long 时间戳,最后统一换算,减少浮点运算次数
  • Windows 上若启用了 “Timer resolution” 工具(如 PowerCfg /energy or LatencyMon),可能强制系统使用更低分辨率计时器,IsHighResolution 会返回 false,此时 GetTimestamp() 实际退化为低精度 API

Stopwatch.GetTimestamp() 在 .NET 6+ 跨平台行为差异

.NET 5 开始统一了各平台计时器抽象,但底层实现仍有区别:Linux 默认用 clock_gettime(CLOCK_MONOTONIC)macOS 用 mach_absolute_time(),而 Windows 优先用 RDTSC(带序列化)或 QueryPerformanceCounter。这意味着即使 Frequency 相同,多次调用的抖动特征也不同。

最易被忽略的一点:**某些虚拟机(特别是旧版 Hyper-V 或 VMWare Workstation)会禁用 TSC 或模拟低频计数器,导致 Frequency 只有 10 MHz 甚至更低,且 GetTimestamp() 调用延迟剧烈波动**。这不是 bug,是虚拟化层有意为之的安全/兼容性策略。

  • 上线前务必在目标环境运行 Stopwatch.IsHighResolution && Stopwatch.Frequency > 1_000_000 校验
  • 容器环境(如 Docker on WSL2)同样受宿主机虚拟化影响,GetTimestamp() 在 WSL2 中实际走的是 Windows 主机的 QPC,但存在额外上下文切换开销
  • .NET 7+ 新增 System.Diagnostics.Metrics,对高频指标采集更友好,但底层仍依赖 Stopwatch —— 所以理解 GetTimestamp() 的本质,比换新 API 更关键

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

334

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

108

2025.10.23

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

765

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

377

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

32

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

29

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

103

2026.02.06

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

99

2025.12.01

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.5万人学习

Git 教程
Git 教程

共21课时 | 4.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号