首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在.NET / C#中获取刻度精度的时间戳?

如何在.NET / C#中获取刻度精度的时间戳?
EN

Stack Overflow用户
提问于 2018-03-19 02:57:59
回答 2查看 0关注 0票数 0

到目前为止,我用于DateTime.Now获取时间戳,但我注意到,如果DateTime.Now在一个循环中打印,会看到它在不连续跳跃时增加约。15毫秒。但是对于我的应用程序中的某些场景,我需要获得最准确的时间戳,最好使用tick(= 100 ns)精度。有任何想法吗?

更新:

显然,StopWatch/ QueryPerformanceCounter是要走的路,但它只能用于测量时间,所以我在考虑调用DateTime.Now应用程序何时启动,然后只是StopWatch运行,然后将经过的时间添加StopWatch到返回的初始值DateTime.Now。至少应该给我准确的相对时间戳,对吗?你怎么看待这个?

注意:

StopWatch.ElapsedTicks不同于StopWatch.Elapsed.Ticks!我用前者假设1个tick = 100ns,但在这种情况下1个tick = 1 / StopWatch.Frequency。所以得到相当于DateTime使用的滴答StopWatch.Elapsed.Ticks。我刚刚学会了这个难题。

笔记2:

使用StopWatch方法,我发现它与实时不同步。大约10个小时后,它超前了5秒。所以我想我们不得不重新同步它每隔X左右,其中X可能是1小时,30分钟,15分钟等我不确定什么是最佳时间再同步将是因为每个resync会改变偏移量可以是最多20毫秒。

EN

回答 2

Stack Overflow用户

发布于 2018-03-19 11:12:52

DateTime.Now读取的系统时钟值每15 ms左右更新一次(或在某些系统上为10 ms),这就是为什么时间量化在这些时间间隔周围的原因。由于代码运行在多线程操作系统中,因此会产生额外的量化效应,因此应用程序并不处于“活动状态”,因此无法测量实际当前时间。

既然你正在寻找一个超精确的时间标记值(而不是仅仅计算一个任意的持续时间),那么这个Stopwatch类本身就不会满足你所需要的。我认为你必须自己做一个DateTime/ Stopwatch混合动力。当应用程序启动时,将存储当前DateTime.UtcNow值(即应用程序启动时的原始分辨率时间),然后启动一个Stopwatch对象,如下所示:

代码语言:txt
复制
DateTime _starttime = DateTime.UtcNow;
Stopwatch _stopwatch = Stopwatch.StartNew();

然后,每当你需要一个高分辨率的DateTime值时,你会得到这样的结果:

代码语言:txt
复制
DateTime highresDT = _starttime.AddTicks(_stopwatch.Elapsed.Ticks);

还可能需要定期重置_starttime和_stopwatch,以避免产生的时间与系统时间过度不同步(尽管我不确定这是否会发生,而且无论如何都需要很长时间才会发生) 。

由于看起来Stopwatch 确实与系统时间同步(每小时多达半秒),我认为DateTime根据在检查调用之间传递的时间量重置混合类是有意义的时间:

代码语言:txt
复制
public class HiResDateTime
{
    private static DateTime _startTime;
    private static Stopwatch _stopWatch = null;
    private static TimeSpan _maxIdle = 
        TimeSpan.FromSeconds(10);

    public static DateTime UtcNow
    {
        get
        {
            if ((_stopWatch == null) || 
                (_startTime.Add(_maxIdle) < DateTime.UtcNow))
            {
                Reset();
            }
            return _startTime.AddTicks(_stopWatch.Elapsed.Ticks);
        }
    }

    private static void Reset()
    {
        _startTime = DateTime.UtcNow;
        _stopWatch = Stopwatch.StartNew();
    }
}

如果以某个固定时间间隔(例如每小时或某些时间)重置混合计时器,则会有在上次读取时间之前设置时间的风险,这就像微型夏令时问题。

票数 0
EN

Stack Overflow用户

发布于 2018-03-19 12:35:53

如果你真正关心的实际上是一个独特的时间戳,它是按严格升序排列的,并且尽可能接近系统时间,你可以尝试这种替代方法:

代码语言:txt
复制
public class HiResDateTime
{
   private static long lastTimeStamp = DateTime.UtcNow.Ticks;
   public static long UtcNowTicks
   {
       get
       {
           long orig, newval;
           do
           {
               orig = lastTimeStamp;
               long now = DateTime.UtcNow.Ticks;
               newval = Math.Max(now, orig + 1);
           } while (Interlocked.CompareExchange
                        (ref lastTimeStamp, newval, orig) != orig);

           return newval;
       }
   }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100003196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档