调度程序计时器无法准确工作

本文关键字:工作 计时器 调度程序 | 更新日期: 2023-09-27 17:59:21

我需要每秒拍摄 10 帧的实时摄像机 15 分钟。我使用了调度器计时器类,但似乎它不能准确工作。如何使其准确?我什至不保存图像,因为它很耗时,我只是将其保存在内存中,但仍然无法正常工作。我应该使用其他库吗?

counter01 = new DispatcherTimer();
counter01.Tick += new EventHandler(counter01_Tick);
counter01.Interval = new TimeSpan(0, 0, 0,100); // every 100 milliseconds == 10 frames per seconds

调度程序计时器无法准确工作

MSDN 声明:

计时器不保证在时间间隔发生时准确执行, 但保证它们在时间间隔发生之前不会执行。

您可以检查秒表,它可能会对您有所帮助。

它尽可能准确。 这要求 UI 线程具有响应能力,快速调度它获得的任何消息。 包括 DispatcherTimer 生成的"时间到了"通知,即生成 Tick 事件的通知。

看到 DispatcherTimer 延迟触发 Tick 事件处理程序的常见挂断是你有一个消防水带问题。 换句话说,事件处理程序所需的时间量比计时器的 Interval 属性值。 这会以您期望的方式自行处理,每当您尝试做超出机器处理能力的事情时,无论您尝试做什么,都会稍后运行。

视频不乏消防问题,一帧可以包含大量数据。 典型的 hidef 视频流以每秒 25 帧的速度运行,每帧包含 1920x1080 像素。 即 25 x 1920 x 1080 x 3 = 148 兆字节/秒。 由于无法解压缩开销,您甚至无法以该速率将数据写入磁盘。 大多数消费级磁盘驱动器的最高速度为 30 MB/秒,给出或接受 2 的系数。 将帧速率降低到 10/秒不足以解决它,仍然是 60 MB/秒,您必须采取更激烈的措施,例如减小帧大小。 或者使用可以实时压缩视频的优质视频编码器。

这是一个系统性问题,而不是调度程序计时器问题。 使用探查器获得更多见解,它可以帮助您识别真正的瓶颈。

您实际上可以让DispatcherTimer在一台好的 PC 上每 100 毫秒执行一次 DispatcherTimer.Tick 事件,但您必须先解决 2 个问题(见下文(。但是,正如其他人在这里正确写的那样,帧的处理也需要一些时间,如果帧处理本身需要大约 100 毫秒,则最快的可靠时钟周期频率可能只有每秒 5 个时钟周期。

1(选择更高的DispatcherTimer.Priority

DispatcherTimer在 WPF GUI 线程上运行。这样做的优点是DispatcherTimer.Tick代码可以访问任何 WPF 控件。WPF GUI 线程由一个Dispatcher控制,该具有 WPF GUI 线程要执行的活动的优先级队列。渲染相关活动的优先级高于DispatcherTimer默认值的优先级。DispatcherTimer的默认优先级为 DispatcherPriority.Background 。有了这个优先级,Tick 在我的 PC 上的执行速度不会超过每 100..300 毫秒。但是,像这样创建计时器:new DispatcherTimer (DispatcherPriority.Input),它将触发大约 100..200 毫秒。渲染仍将具有更高的优先级,因此用户不会获得冻结的 GUI。

2(提高刻度规律性

DispatcherTimer的一个问题是,如果 Tick 事件由于 WPF GUI 线程忙于其他活动而延迟 x 毫秒,则下一个 Tick 仍将等待 100+ 毫秒。但是,如果将DispatcherTimer.Interval缩短 x 毫秒,则会更频繁地触发 tick 事件。

有关更多详细信息,请参阅我的文章 CodeProject:提高 WPF 调度程序计时器精度

最后考虑

为什么要处理 WPF GUI 线程上的帧?仅当 Tick 事件与 Tick 事件无关且需要访问 WPF 控件时,才使用 DispatcherTimer。但是,如果您需要每 100 毫秒执行相当多的代码,最好使用额外的线程。您的 CPU 具有不同的内核,最好将工作负载分布在 2 个内核上。