【发布时间】:2010-06-29 13:00:26
【问题描述】:
Related to my previous question,但是对于 C#,我需要精确的系统时间,包括毫秒。
C# 时间函数的精度高达 10 到 15 毫秒,但不完全是 1 毫秒。
队列性能计数器也是如此。有没有其他方法可以精确到毫秒?
【问题讨论】:
Related to my previous question,但是对于 C#,我需要精确的系统时间,包括毫秒。
C# 时间函数的精度高达 10 到 15 毫秒,但不完全是 1 毫秒。
队列性能计数器也是如此。有没有其他方法可以精确到毫秒?
【问题讨论】:
Windows 不想每秒更新 1000 次系统时钟来浪费电力,所以默认是每秒只更新 60-100 次。如果将多媒体定时器设置为 1ms,则可以从时钟获得 1ms 的分辨率,但不建议这样做。
为了详细说明节电,当 CPU 闲置一段时间时会发生什么情况,即它可以进入非常低功耗的状态。每当它被中断(例如增加时钟滴答声)时,它必须离开其极低功耗状态并使用大量电力来为整个 CPU 供电以服务该中断。换句话说,额外的功能不是增加时钟滴答,而是让 CPU 保持清醒。
由于我的笔记本电脑在时钟频率为 60Hz 时使用 10W,而在 1000Hz 时使用 11W,而我的电池续航时间为 300 分钟,因此较慢的时钟使我的电池续航时间增加了近 30 分钟!
【讨论】:
timer interrupt。尽管 Windows 在电力效率方面远非擅长(比 android 效率低 50%,比 mac OS 低 20%),但它确实没有理由让它变得更糟。内核滴答用于调用过期(或合并)的计时器回调、重新更新线程/进程调度以及增加全局操作系统滴答计数。
DateTime.Now 不够准确,但您没有展示如何提高准确性...
您可以使用 this DateTimePrecise class 在 .NET 中获得高精度时间
更新
CodeProject 链接不再有效。我已提取代码from archive.org 并将其嵌入此处以供将来参考。此代码“按原样”包含在此处,与 CodeProject 页面中包含的完全相同。
DateTimePrecise和DateTime.Now一样好用,只不过@987654326@是实例方法而不是静态方法,所以你要先实例化一个DateTimePrecise。
using System.Diagnostics;
/// DateTimePrecise provides a way to get a DateTime that exhibits the
/// relative precision of
/// System.Diagnostics.Stopwatch, and the absolute accuracy of DateTime.Now.
public class DateTimePrecise
{
/// Creates a new instance of DateTimePrecise.
/// A large value of synchronizePeriodSeconds may cause arithmetic overthrow
/// exceptions to be thrown. A small value may cause the time to be unstable.
/// A good value is 10.
/// synchronizePeriodSeconds = The number of seconds after which the
/// DateTimePrecise will synchronize itself with the system clock.
public DateTimePrecise(long synchronizePeriodSeconds)
{
Stopwatch = Stopwatch.StartNew();
this.Stopwatch.Start();
DateTime t = DateTime.UtcNow;
_immutable = new DateTimePreciseSafeImmutable(t, t, Stopwatch.ElapsedTicks,
Stopwatch.Frequency);
_synchronizePeriodSeconds = synchronizePeriodSeconds;
_synchronizePeriodStopwatchTicks = synchronizePeriodSeconds *
Stopwatch.Frequency;
_synchronizePeriodClockTicks = synchronizePeriodSeconds *
_clockTickFrequency;
}
/// Returns the current date and time, just like DateTime.UtcNow.
public DateTime UtcNow
{
get
{
long s = this.Stopwatch.ElapsedTicks;
DateTimePreciseSafeImmutable immutable = _immutable;
if (s < immutable._s_observed + _synchronizePeriodStopwatchTicks)
{
return immutable._t_base.AddTicks(((
s - immutable._s_observed) * _clockTickFrequency) / (
immutable._stopWatchFrequency));
}
else
{
DateTime t = DateTime.UtcNow;
DateTime t_base_new = immutable._t_base.AddTicks(((
s - immutable._s_observed) * _clockTickFrequency) / (
immutable._stopWatchFrequency));
_immutable = new DateTimePreciseSafeImmutable(
t,
t_base_new,
s,
((s - immutable._s_observed) * _clockTickFrequency * 2)
/
(t.Ticks - immutable._t_observed.Ticks + t.Ticks +
t.Ticks - t_base_new.Ticks - immutable._t_observed.Ticks)
);
return t_base_new;
}
}
}
/// Returns the current date and time, just like DateTime.Now.
public DateTime Now
{
get
{
return this.UtcNow.ToLocalTime();
}
}
/// The internal System.Diagnostics.Stopwatch used by this instance.
public Stopwatch Stopwatch;
private long _synchronizePeriodStopwatchTicks;
private long _synchronizePeriodSeconds;
private long _synchronizePeriodClockTicks;
private const long _clockTickFrequency = 10000000;
private DateTimePreciseSafeImmutable _immutable;
}
internal sealed class DateTimePreciseSafeImmutable
{
internal DateTimePreciseSafeImmutable(DateTime t_observed, DateTime t_base,
long s_observed, long stopWatchFrequency)
{
_t_observed = t_observed;
_t_base = t_base;
_s_observed = s_observed;
_stopWatchFrequency = stopWatchFrequency;
}
internal readonly DateTime _t_observed;
internal readonly DateTime _t_base;
internal readonly long _s_observed;
internal readonly long _stopWatchFrequency;
}
【讨论】:
Date.UtcNow 作为其基础,然后使用系统的高精度计时器计算自UtcNow 以来的时间。因为它源自DateTime.UtcNow,所以它永远不会比这更准确。您还应该检查您的硬件的Stopwatch.Frequency,以确定高精度功能是否确实有效。
尝试System.Diagnostics.Stopwatch 以获得高分辨率计时。
如果安装的硬件和 操作系统支持 高分辨率性能计数器, 然后秒表类使用它 计数器来测量经过的时间。 否则,秒表类使用 测量经过的系统计时器 时间。
尝试原生DateTime.Ticks,系统时间精度高达一百纳秒; 1 毫秒 = 10000 个滴答声。
while (true)
{
System.Threading.Thread.Sleep(1);
Console.WriteLine("{0} {1}",
System.DateTime.Now.Ticks,
System.DateTime.Now.ToString("ss:fff"));
}
PS > .\test.exe
634134152924322129 52:432
634134152924332129 52:433
634134152924342130 52:434
634134152924352130 52:435
634134152924362131 52:436
634134152924372131 52:437
634134152924382132 52:438
634134152924392133 52:439
634134152924402133 52:440
634134152924412134 52:441
634134152924422134 52:442
634134152924432135 52:443
【讨论】:
DateTime.Ticks 并不比DateTime.Millisecond 更准确。在内部,DateTime.Millisecond 调用 DateTime.Ticks