如何使用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/

标签:C#,Stopwatch,微秒级精确度
0
投稿

猜你喜欢

  • Android导航栏功能项的显示与屏蔽介绍

    2022-09-27 06:38:55
  • java如何将int数组转化为Integer数组

    2021-07-19 04:22:37
  • Java实现统计字符串出现的次数

    2022-12-19 01:06:52
  • Kotlin Flow数据流的3种使用场景详解

    2021-06-03 09:06:18
  • 在C# WPF下自定义滚动条ScrollViewer样式的操作

    2022-09-17 16:55:28
  • servlet之session简介_动力节点Java学院整理

    2023-07-07 00:51:07
  • C#装箱和拆箱原理详解

    2021-12-29 16:07:26
  • JVM教程之内存管理和垃圾回收(三)

    2023-11-10 15:49:54
  • 教你用Java在个人电脑上实现微信扫码支付

    2023-07-22 20:52:15
  • Android Handler移除Message详解及实例代码

    2022-04-07 06:51:00
  • C#统计字符串的方法

    2021-06-12 17:00:12
  • 手把手教你JAVA进制之间的转换

    2023-11-14 23:18:56
  • Android实现GPS定位代码实例

    2022-07-14 17:26:21
  • Flutter Widgets之标签类控件Chip详解

    2023-06-26 14:22:35
  • 在Winform动态启动、控制台命令行的方法

    2021-11-02 05:11:07
  • Android 自定义按钮点击事件和长按事件对比

    2023-06-04 00:57:14
  • Android中的深度链接技术实战

    2023-09-20 11:27:18
  • Unity快速生成常用文件夹的方法

    2023-12-11 20:37:43
  • C#实现按照指定长度在数字前补0方法小结

    2023-02-23 09:42:32
  • Android优化提升应用启动速度及Splash页面的设计

    2022-02-18 06:02:27
  • asp之家 软件编程 m.aspxhome.com