如何使用C# Stopwatch 测量微秒级精确度
作者:黑暗执行绪 发布时间:2021-09-14 04:31:04
跟同事讨论到- 用C# Stopwatch 取得效能数值,Stopwatch.ElapsedMilliseconds 只到毫秒(ms),如果需要更高的时间精确度(微秒μs,甚至奈秒ns),该怎么做?
原以为要费番功夫,在Stackoverlow查到讨论,答案意外地简单。
准备测试程式如下,比较MD5 及SHA1 计算1MB byte[] 杂凑值所秏费时间:
static byte[] data = new byte[1024 * 1024];
static void Main(string[] args)
{
Test1();
Console.ReadLine();
}
private static void Test1()
{
Console.WriteLine("Test 1");
for (var i = 0; i < 5; i++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var md5 = MD5.Create().ComputeHash(data);
sw.Stop();
Console.WriteLine($"MD5 {sw.ElapsedMilliseconds}ms");
sw.Restart();
var sha1 = SHA1.Create().ComputeHash(data);
sw.Stop();
Console.WriteLine($"SHA1 {sw.ElapsedMilliseconds}ms");
}
}
执行结果如下:
Test 1
MD5 10ms
SHA1 2ms
MD5 2ms
SHA1 2ms
MD5 2ms
SHA1 2ms
MD5 2ms
SHA1 2ms
MD5 2ms
SHA1 2ms
有两个问题,第一是回圈的第一次执行因涉及.NET 初始化,耗时会异常偏高(先做SHA1 再做MD5,就变成第一笔SHA1 超过10ms),第二是MD5 与SHA1 执行时间相近,都是2ms 多,用ElapsedMilliseconds 看不出差异。
针对首次数值耗时偏差问题,除了略过第一次数据不计,我想到的另一个解法是在Test1()前先跑一次MD5.Create()完成相关初始化。至于ElapsedMilliseconds看不出差异问题,改用ElapsedTicks是种解法,但要注意,ElaspedTicks换算成时间单位时,不是除以TimeSpan.TicksPerMillisecond而是依CPU频率而定,需使用Stopwatch.Frequency (每秒Tick数)。
第二版改用ElapsedTicks * 1000000F / Stopwatch.Frequency 计算微秒(Microsecond, μs),执行前先MD5.Create() 暖机。
static byte[] data = new byte[1024 * 1024];
static void Main(string[] args)
{
MD5.Create();
Test2();
Console.ReadLine();
}
private static void Test2()
{
Console.WriteLine("Test 2");
for (var i = 0; i < 5; i++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var md5 = MD5.Create().ComputeHash(data);
sw.Stop();
//
Console.WriteLine($"MD5 {sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
sw.Restart();
var sha1 = SHA1.Create().ComputeHash(data);
sw.Stop();
Console.WriteLine($"SHA1 {sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
}
}
执行结果的第一次时间偏长问题消失,而也呈现出SHA1 比MD5 计算耗时的证据。而由数值来看,精确度可到0.1μs = 100ns。
Test 2
MD5 2,402.200μs
SHA1 2,724.000μs
MD5 2,017.300μs
SHA1 2,576.900μs
MD5 2,102.100μs
SHA1 2,578.700μs
MD5 2,024.100μs
SHA1 2,600.300μs
MD5 2,008.300μs
SHA1 2,624.300μs
自己计算麻烦了点,Stopwatch 有个Elapsed 属性,型别为TimeSpan,其中TotalMilliseconds 属性精确度即可达到μs 及100ns。请看第三版:
static byte[] data = new byte[1024 * 1024];
static void Main(string[] args)
{
MD5.Create();
Test3();
Console.ReadLine();
}
private static void Test3()
{
Console.WriteLine("Test 3");
for (var i = 0; i < 5; i++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var md5 = MD5.Create().ComputeHash(data);
sw.Stop();
Console.WriteLine($"MD5 {sw.Elapsed.TotalMilliseconds * 1000:n3}μs");
sw.Restart();
var sha1 = SHA1.Create().ComputeHash(data);
sw.Stop();
Console.WriteLine($"SHA1 {sw.Elapsed.TotalMilliseconds * 1000:n3}μs");
}
}
执行结果与第二版相同,但程式更简单一些。
Test 3
MD5 2,423.400μs
SHA1 2,692.400μs
MD5 2,204.000μs
SHA1 2,976.800μs
MD5 2,094.500μs
SHA1 2,588.600μs
MD5 2,034.600μs
SHA1 2,598.900μs
MD5 2,029.900μs
SHA1 2,887.000μs
来源:https://blog.darkthread.net/blog/measure-microsecond-with-stopwatch/


猜你喜欢
- 场景在任何一个Form表单的操作页面或者数据台账的查询页面,基本都会看到一个清除的按钮,其功能就是用来清除我们需要抛弃的已经写入到控件内的数
- AQS 同步队列1、AQS 介绍AQS 是 AbstractQueuedSynchronizer 的缩写,他是一个抽象同步类,为 JUC 包
- 1、导包,四大核心包,一个切面包(AOP),logging,web,springmvc2、配置文件,核心代码如下:web.xml<se
- 多线程run方法中直接调用service业务类应注意Java多线程run方法里边使用service业务类会产生java.lang.NullP
- 第一篇讲了文件的基本概念,和文件如何打开和关闭。第二篇主要介绍文件的顺序读写和随机读写。外加文件缓冲区的知识点。文件的顺序读写字符输入输出f
- 站点IP访问频率限制 针对单个站点using System;using System.Collections.Generic;u
- AudioSource 组件参考属性属性说明Clip音频资源Volume音量大小Mute是否静音Loop是否循环Play on load加载
- 在ibatis的xml文件里,我们去写sql语句,对应mapper类的方法,这些sql语句与控制台上没什么两样,但在有些功能上需要注意,如w
- 一、定时任务的使用场景和常见的定时任务某个时间定时处理某个任务、发邮件、短信、消息提醒、订单通知、统计报表等定时任务划分单机定时任务:单机的
- 在前一期中,我们做了悬浮头部的两个tab切换和下拉刷新效果,后来项目中要求改成三个tab,当时就能估量了一下,如果从之前的改,也不是不可以,
- BottomNavigationView 很早之前就在 Material Design 中出现了,但是直到 Android Support
- 1)下载sqlite jdbc驱动http://www.xerial.org/maven/repository/artifact/org/x
- 前言话不多说,直接上图:笔者使用 RecyclerView 的 ItemTouchHelper 来实现这个效果,过程非常简单。为了学习,这里
- mybatis-plus想要修改某字段为null问题场景使用mybatis + mybatisPlus进行修改某字段,想要将其设为null,
- 1、同步消息即时性较强,重要的消息,且必须有回执的消息,例如短信,通知(转账成功)生产者:public class Producer { &
- 现在网上很多应用都是用二维码来分享网址或者其它的信息。尤其在移动领域,二维码更是有很大的应用场景。因为项目的需要,需要在网站中增加一个生成二
- Flyway是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。第一步:pom.xml添加maven依赖<!-- https
- 目录1.说明2.先来说下@FunctionalInterface3. 下面来讲讲这个 "::"是干嘛的4. 建立一个Pe
- 目录1、通过session中的token验证步骤1:创建自定义注解步骤2:创建自定义 * (@slf4j是lombok的注解)步骤3:将自定
- 前言做APP应用开发的时候,用户头像肯定是必不可少的,但是90%以上的需求头像都是圆形的。那么,如何通过自定义View的方式实现圆形头像呢,