【问题标题】:Looking for millisecond precision logging in windows application在 Windows 应用程序中寻找毫秒精度的日志记录
【发布时间】:2013-05-24 06:44:21
【问题描述】:

最近我正在为我的 Windows 应用程序寻找解决方案,这会导致不正确的日志记录落后文件.. 我发现 Windows datetime.now 的解决时间问题 所以,我试图避免这种情况。我根据表单答案中给出的可能提示创建了示例应用程序......

这是示例代码及其输出......

private Timer tmr = new Timer();
private Stopwatch ss;

void tmr_Tick( object sender, EventArgs e )
{
     WriteData();
}

private void button1_Click( object sender, EventArgs e )
{
     ss = new Stopwatch();
     ss.Start();
     tmr.Interval = 1;
     tmr.Tick += new EventHandler( tmr_Tick );
     tmr.Start();
     WriteData();
}
void WriteData()
{
     Console.WriteLine(ss.ElapsedMilliseconds);
}

输出: 0 19 29 49 69 79 99 109 122 142 162 172 192 202 222 232 252 282 272 294 314 334 341

我怎样才能在这段代码中获得更高的准确性....????

【问题讨论】:

  • @I4V - 那篇文章有点过时了,因为 Stopwatch 做了同样的事情,也就是说,它是将“HiResTimer”集成到 2.0 后的框架中的结果。
  • @I4V 是的,就像 jamesmus 说的那样,那篇文章现在已经过时了。您只需使用秒表。

标签: c# windows logging


【解决方案1】:
 tmr.Interval = 1;

这是一个很小的数字,无法将其变小是一种美德。但是不,你不会得到一个每秒滴答一千次的计时器。决定 Timer 触发 Tick 事件的实际速率的三个因素:

  • 您的 UI 线程在做其他事情时有多忙。就像运行 Click 事件处理程序或绘制窗口一样。 Tick 事件处理程序只能在 UI 线程不忙于任何事情时运行,它必须是 idle。这当然是一个高度可变的数字,对于您的应用程序的用户正在做什么非常重要。他可以做的一些事情非常昂贵,比如调整应用程序的窗口大小。典型的 UI 线程任务,如绘画,需要几毫秒。对人眼来说足够快,但如果您需要该 Tick 事件如此频繁地运行,则非常明显。它只是不会运行,如果你的 UI 很复杂,可能需要数百毫秒。您需要另一种 Timer 类来避免这种情况,System.Threading.Timer 或 System.Timers.Timer。它们是在线程池线程上运行代码的计时器类。其优点是它不会被 UI 线程中发生的事情延迟。还有一个明显的缺点是你必须非常小心你在代码中所做的事情,你当然不能更新 UI。

  • 机器做其他事情有多忙。就像执行另一个进程或设备驱动程序的线程一样。这是操作系统的主要任务,允许数百个线程共享处理器。 Windows 中的线程调度程序确定线程何时有机会运行。一旦它获得处理器并执行,它就可以运行一段时间,这段时间称为量子。对于前台窗口所拥有的线程,典型的时间间隔是 45 毫秒。其他线程暂停,直到它们有机会运行。这当然意味着你计划每秒运行一千次 Tick 事件的计划。您需要仔细控制机器上运行的其他程序,多核处理器会有很大帮助。

  • Windows 更新计时器的频率。与之相关的核心操作系统功能是时钟中断。用于很多事情,它是操作系统的基本心跳。处理器的正常状态是什么都不做,它是关闭的。时钟滴答中断将其从暂停状态唤醒,操作系统检查是否需要执行任何工作。默认中断率为每秒 64 次,每 15.625 毫秒一次。这也会影响计时器的准确性,当处理器停止时不会发生任何事情。所以按照设计,你永远不会得到 1 毫秒的速率,它永远不会低于 16 毫秒。

后一个子弹肯定是最大的问题。实际上,您可以更改程序中的中断率,它需要对 timeBeginPeriod() winapi 函数进行 pinvoke 调用。 This answer 显示如何。还提到了 timeSetEvent() 函数,您需要在任何接近计时器的地方获得该函数,该计时器具有能够维持 1 毫秒速率的合理保证。

【讨论】:

  • 我赞成你,因为这是对一些计时器机制的详细描述。我将最初的问题解释为关于秒表的分辨率,计时器只是用作一种探索性(即丢弃)机制来检查它。不过重读,其实还不是很清楚!
【解决方案2】:

Stopwatch 在后台使用 Windows 性能计数器 API,因此它应该非常准确(性能计数器 API 被引用为具有低微秒范围内的分辨率)。

不过,您的测试无效,因为您实际上是在测量计时器中的漂移,而不是秒表中的任何不准确性。

关于 Timer 的主题 - 看起来您在示例中使用了 System.Windows.Forms.Timer 类。这不是准确性的好选择。它的唯一优点是它会在 UI 线程上引发 Tick 事件。请尝试使用 System.Threading.Timer 类 - 您可能会发现它的结果更接近您的预期(尽管仍然存在一些偏差)。

var timerCallback = (TimerCallback)(sw => Console.WriteLine(((Stopwatch)sw).Elapsed));
var timerInterval = TimeSpan.FromMilliseconds(1);
var stopwatch = Stopwatch.StartNew();
var timer = new Timer(timerCallback, stopwatch, timerInterval, timerInterval);

最终,要测试秒表的准确性是相当困难的,因为没有任何其他现成的东西比它更准确!

【讨论】:

    猜你喜欢
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    相关资源
    最近更新 更多