即将在 IDL 8.6 中推出 - 重复定时器
原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/coming-in-idl-86-repeating-timers
14171 为本文评分:
暂无评分
即将在 IDL 8.6 中推出 - 重复定时器
Jim Pendleton 2016年7月14日,星期四
几年前,我写过一篇博客文章,主题是关于 IDL 8.3 中的新 TIMER 类。在即将发布的 IDL 8.6 版本中,Timer::Set 方法将新增一个 REPEAT 关键字。
NV5 的自定义解决方案组 喜欢编写设备控制软件,因此这个新功能将会派上用场。
使用带有 REPEAT 功能的定时器的典型场景,源于需要确保以固定时间间隔进行处理的需求。例如,以特定的每秒帧率显示动画,或者以稳定的频率从设备采集数据。
这个 REPEAT 关键字是一个开关,用于强制定时器按照指定的时间间隔触发。这使得回调代码无需在处理前一个事件时显式调用手动重置定时器。它产生了一个真正规律的事件"心跳"。
当回调函数的处理时间小于定时器的触发间隔时,最适合使用这种风格的定时器。如果定时器事件加入队列的速度高于其被处理消耗的速度,则通常不推荐使用此解决方案,或者需要相应地调整时间间隔。
应使用 IDL 代码探查器 来确定回调执行时间与采样率之间是否存在潜在冲突。同时请注意,您的测量结果将取决于当前平台和系统负载,因此在将此类解决方案部署到与测试设备性能特征不同的其他计算机上时,需要谨慎判断。
可以将定时器回调视为对主 IDL 解释器循环的更高优先级中断。它将优先于其他正在执行的代码。
当解释器在执行 .pro 代码行之间时,如果发现队列中有定时器事件,则定时器的回调例程将首先执行,优先于下一行 IDL 代码。这也适用于 IDL SAVE 文件中的编译代码。
当回调完成后,解释器将返回到其常规调度的执行中,这可能包括处理其他定时器回调。
换句话说,IDL 解释器保持单线程。定时器回调将作为对当前执行上下文的中断来执行。实际上,定时器甚至可以中断模态的 WIDGET_BASE 对话框。在许多情况下,明智的做法可能是使用诸如 TIMER 的 ::Block/::Unblock 方法或系统信号量等机制来防止重入的可能性。
示例
以下源代码显示了设置 /REPEAT 时定时器事件队列的行为。
PRO myTimerCallback3, id, c
COMPILE_OPT IDL2
t = systime(1)
c.dt.add, t - c.t
c.t = t
c.counter++
wait, c.counter ge 20 && c.counter le 40 ? .51 : .001
print, 'in callback ', c.counter
done = c.counter eq 100
if (done) then begin
p = plot(c.dt.toarray(), ytitle = 'dt', xtitle = 'iteration', $
title = 'Execution time per iteration')
void = Timer.Cancel(id)
endif
END
PRO async_timer_example_repeat3
COMPILE_OPT IDL2
; 创建一个每秒触发5次的定时器。
c = {counter : 0L, t : systime(1), dt : list()}
id = Timer.Set( 0.2, 'myTimerCallback3', c, /REPEAT )
END
创建了一个新的定时器对象,该对象以 0.2 秒的间隔触发事件,无论 IDL 主线程中可能还有其他什么任务正在执行。
在回调中,前 19 次迭代仅执行 1 毫秒的 WAIT 延迟,模拟了较轻的 CPU 负载。
第 20 到 40 次迭代执行时带有 0.51 秒的延迟,这超过了定时器对象重复间隔的两倍。这模拟了较重的 CPU 负载,并有助于说明定时器在后台继续以其自身的速率运行和排队事件。
剩余的步骤恢复为较短的等待时间。
在内部,代码跟踪每一步回调执行之间的时钟时间。
结果绘图如下所示。

图中的标签指示了每个时间间隔内执行速率的主导因素。
最初,定时器的"心跳"使我们保持正常的 0.2 秒回调间隔。
下一组迭代主要由每个回调内部的 0.51 秒 WAIT 主导。如果我们在显示视频播放,那么在此期间帧率将大幅下降。
第三组迭代显示了清空队列中累积的定时器事件的效果。这些事件在触发时由于前一个代码块中的 WAIT 语句而未能被立即处理。如果这是视频播放,这些帧将会非常快速地全部显示出来。
队列清空后,再次达到规律的"心跳"。视频播放将恢复到"实时"状态。
如果您移除 /REPEAT 关键字,并在回调例程中添加对 Timer::Set 的调用,则可以比较效果。在您自己的代码中如何选择,将基于您对"实时"采样与"有延迟但稳定"采样的优先级考量。