首页 > 编程语言 >C# 六种方式实现精确计时

C# 六种方式实现精确计时

时间:2023-12-18 22:26:46浏览次数:27  
标签:调用 毫秒 C# System 六种 API GetTickCount 计时 Stopwatch

C# 六种方式实现精确计时

C# 六种方式实现精确计时

翔星 翔星 有10年+工作经验,高级软件工程师,可以解决各种问题   你经常看 TA 的内容

根据综合网上的一些文章,精确计时主要有以下几种方式

1 调用WIN API中的GetTickCount

[DllImport("kernel32")]static extern uint GetTickCount();

从操作系统启动到现在所经过的毫秒数,精度为1毫秒,经简单测试发现其实误差在大约在15ms左右

缺点:返回值是uint,最大值是2的32次方,因此如果服务器连续开机大约49天以后,该方法取得的返回值会归零

用法:

uint s1 = GetTickCount();Thread.Sleep(2719);Console.WriteLine(GetTickCount() - s1); //单位毫秒

2 调用WIN API中的timeGetTime推荐

[DllImport("winmm")]static extern uint timeGetTime();

常用于多媒体定时器中,与GetTickCount类似,也是返回操作系统启动到现在所经过的毫秒数,精度为1毫秒。

一般默认的精度不止1毫秒(不同操作系统有所不同),需要调用timeBeginPeriod与timeEndPeriod来设置精度

[DllImport("winmm")]static extern void timeBeginPeriod(int t);[DllImport("winmm")]static extern void timeEndPeriod(int t);

缺点:与GetTickCount一样,受返回值的最大位数限制。

用法:

timeBeginPeriod(1);uint start = timeGetTime();Thread.Sleep(2719);Console.WriteLine(timeGetTime() - start); //单位毫秒timeEndPeriod(1);

3 调用.net自带的方法System.Environment.TickCount

获取系统启动后经过的毫秒数。经反编译猜测它可能也是调用的GetTickCount,但是它的返回值是int,而GetTickCount与timeGetTime方法的原型中返回值是DWORD,对应C#中的uint,难道.NET对System.Environment.TickCount另外还做了什么处理么?
缺点:与GetTickCount一样,受返回值的最大位数限制。

用法:

int aa = System.Environment.TickCount;Thread.Sleep(2719);Console.WriteLine(System.Environment.TickCount - aa); //单位毫秒

:经过测试,发现GetTickCount、System.Environment.TickCount也可以用timeBeginPeriod与timeEndPeriod来设置精度,最高可将精度提高到1毫秒。不知是什么原因?

4 调用WIN API中的QueryPerformanceCounter

[DllImport("kernel32.dll ")]static extern bool QueryPerformanceCounter(ref long lpPerformanceCount);

用于得到高精度计时器(如果存在这样的计时器)的值。微软对这个API解释就是每秒钟某个计数器增长的数值。
如果安装的硬件不支持高精度计时器,函数将返回false需要配合另一个API函数QueryPerformanceFrequency。

[DllImport("kernel32")]static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);

QueryPerformanceFrequency返回硬件支持的高精度计数器的频率,如果安装的硬件不支持高精度计时器,函数将返回false。

用法:

long a = 0;QueryPerformanceFrequency(ref a);long b = 0, c = 0;QueryPerformanceCounter(ref b);Thread.Sleep(2719);QueryPerformanceCounter(ref c);Console.WriteLine((c - b) / (decimal)a); //单位秒

精度为百万分之一秒。而且由于是long型,所以不存在上面几个API位数不够的问题。

缺点:在一篇文章看到,该API在节能模式的时候结果偏慢,超频模式的时候又偏快,而且用电池和接电源的时候效果还不一样(笔记本)
原文地址:http://delphi.xcjc.net/viewthread.php?tid=1570
未经过超频等测试,如果是真的,那该API出来的结果就可能不准。

5 使用.net的System.Diagnostics.Stopwatch类推荐

Stopwatch 在基础计时器机制中对计时器的刻度进行计数,从而测量运行时间。如果安装的硬件和操作系统支持高分辨率性能的计数器,则 Stopwatch 类将使用该计数器来测量运行时间;否则,Stopwatch 类将使用系统计数器来测量运行时间。使用 Frequency 和 IsHighResolution 两个静态字段可以确定实现 Stopwatch 计时的精度和分辨率。

实际上它里面就是将QueryPerformanceCounter、QueryPerformanceFrequency两个WIN API封装了一下,如果硬件支持高精度,就调用QueryPerformanceCounter,如果不支持就用DateTime.Ticks来计算。

用法:

Stopwatch sw = new Stopwatch();sw.Start();Thread.Sleep(2719);sw.Stop();Console.WriteLine(sw.ElapsedTicks / (decimal)Stopwatch.Frequency);

6 使用CPU时间戳进行更高精度计时

原文地址:http://www.chinaunix.net/jh/23/110190.html

该方法的原理我不是很明白,硬件知识太匮乏了。精度是ns

在C#中要用该方法必须先建立一个托管C++项目(因为要内嵌汇编),编译成DLL供c#调用,有点麻烦。

C++代码:

// MLTimerDot.h #pragma once using namespace System; namespace MLTimerDot { //得到计算机启动到现在的时钟周期 unsigned __int64 GetCycleCount(void) { _asm _emit 0x0F _asm _emit 0x31 } //声明 .NET 类 public __gc class MLTimer { public: MLTimer(void) { } //计算时钟周期 UInt64 GetCount(void) { return GetCycleCount(); } };}

C#调用:

long a = 0;QueryPerformanceFrequency(ref a);MLTimerDot.MLTimer timer = new MLTimerDot.MLTimer();ulong ss= timer.GetCount();Thread.Sleep(2719);Console.WriteLine((timer.GetCount() - ss) / (decimal)a);

缺点:和QueryPerformanceCounter一样,结果不太稳定。

我的结论:常规应用下timeGetTime完全够用了,将精度调到1毫秒,大部分境况都够用。System.Diagnostics.Stopwatch由于调用方便,也推荐使用

来源公众号:dotNET编程大全

版权声明:本文来源于网友收集或网友供稿,仅供学习交流之用,如果有侵权,请转告小编或者留言,本公众号立即删除。


 

 

 

支持小薇

 

 

关注公众号↑↑↑:DotNet开发跳槽❀点分享点收藏点点赞点在看

标签:调用,毫秒,C#,System,六种,API,GetTickCount,计时,Stopwatch
From: https://www.cnblogs.com/sexintercourse/p/17912505.html

相关文章

  • PyCharm中New Directory 和 New Python Package的区别
    如题,这是一个很简单也很基础的问题,先看不同操作的结果有什么不同结果1:项目下出现了一个空“文件夹” 结果2:项目下多了一个“PythonPackage”,该package下包含了一个“__init__.py”文件,该py文件是空的如果把该py文件删掉后,package也就变成了directory  所以什么是__in......
  • [ABC312C] Invisible Hand
    其他题解都是二分,这里介绍一种\(O(n+m)\)的线性写法。我们尝试考虑在\(x\)为和值时会出现答案?很显然,对于任意\(1\leqi\leqn\)和\(1\leqj\leqm\),\(x\)只可能等于\(a_i\)或\(a_i+1\)或\(b_i\)或\(b_i+1\)。即\(x\)为这\(2\times(n+m)\)种情况中的一......
  • 查看mvn版本:cannot execute binary file
    一、现象二、原因网络资料上大部分的原因是因为jdk不是46位导致失败。其实我这边的原因也查不多,目前使用的是MacM2芯片的电脑但是还安装之前的jdk版本,将其替换为macosarm版本即可。三、操作JDK下载官网下载、解压并更新环境变量四、修复......
  • 不容错过的 13 个顶级 C++ 程序库
    不容错过的13个顶级C++程序库Incredibuild​已认证账号​关注 135人赞同了该文章关于C++,不论是其长达40年的发展历史,或者C++是高级还是低级编程语言的争论等等,这些内容都已老生常谈。如果你对C++库有所研究,不用我多说,大家也都心中......
  • 面试常考:C#用两个线程交替打印1-100的五种方法
    面试常考:C#用两个线程交替打印1-100的五种方法翔星有10年+工作经验,高级软件工程师,可以解决各种问题​关注 你经常看TA的内容"C#用两个线程交替打印1-100的五种方法"是.NET工程师面试多线程常考的试题之一,主要考察对C#语法和对多线程的熟悉程......
  • AtCoder Beginner Contest 324
    C-ErrorCorrection大意是:给定一个字符串a,以及一组字符串,如果字符串与a满足以下之一即可我写的有点麻烦。。#include<bits/stdc++.h>usingnamespacestd;voidsolve(){ intn; cin>>n; strings; cin>>s; vector<int>ans; for(inti=1;i<=n;i++){ stringt; ci......
  • BIgdataAIML-IBM-A neural networks deep dive - An introduction to neural networks
    https://developer.ibm.com/articles/cc-cognitive-neural-networks-deep-dive/ByM.TimJones,PublishedJuly23,2017Neuralnetworkshavebeenaroundformorethan70years,buttheintroductionofdeeplearninghasraisedthebarinimagerecognitionand......
  • 发布 VectorTraits v1.0, 它是C#下增强SIMD向量运算的类库
    发布VectorTraitsv1.0,它是C#下增强SIMD向量运算的类库zyl910吃瓜群众​关注 你经常看C#话题的内容发布VectorTraitsv1.0,它是C#下增强SIMD向量运算的类库VectorTraits:SIMDVectortypetraitsmethods(SIMD向量类型的特征方法).N......
  • 符号执行manticore工具演练之发现缓冲区溢出漏洞
    符号执行之manticore工具演练参考资料:SANSSEC554https://docs.soliditylang.org/en/v0.8.0/ziion虚拟机:区块链智能合约中的kali(ziion涵盖演练中所以提及到的工具)动静态之分IDA是静态分析工具,常用于检测脆弱性;manticore是动态分析工具,常用于编写漏洞利用(符号执行:即执......
  • C# 读写 Excel 四种方案(OpenXml、NPOI、EPPlus、Spire.Office)
    C#读写Excel四种方案(OpenXml、NPOI、EPPlus、Spire.Office)翔星有10年+工作经验,高级软件工程师,可以解决各种问题​关注 你经常看TA的内容前言在项目中需要使用C#读写Excel,每天定时将数据输出到Excel表格中。在参考了很多的方案后,找到了4......