在性能关键软件(Qt)中使用计时器
Using timers with performance-critical software (Qt)
我正在开发一个应用程序,负责通过UDP连接移动和管理机器人。
程序需要:
- 使用SDL读取操纵杆/用户输入
- 每20毫秒生成并向机器人发送一个控制数据包(UDP)
- 接收并解码来自机器人的应答报文(~20 msecs)。这是通过信号/插槽机制实现的,不需要定时器。
- 接收和处理机器人消息,用于调试。
- 定期更新UI,让用户了解机器人的状态(例如电池电压)。在大多数情况下,我也使用了Qt的信号/槽机制。
- 使用看门狗,如果在1秒后没有收到响应,则禁用机器人。当应用程序接收到机器人数据包(~20 msecs) 时,看门狗复位。
目前,我已经实现了上述所有功能。但是,当看门狗被激活或者两个或两个以上的QTimer
对象被使用时,应用程序无法正常发送数据包。应用程序通常可以工作,但我不认为它是"生产就绪"的。我已经尝试使用定时器的精度标志(Qt::Precise
, Qt::Coarse
和Qt::VeryCoarse
),但我仍然遇到问题。
指出:
- 代码通常组织良好,在代码库中没有"上帝对象"(大多数源文件少于150行,只创建必要的依赖项)。
- 大多数情况下,我使用
QTimer::singleShot()
(例如,我只会发送下一个数据包一旦当前数据包已经发送)。
使用计时器的地方:
- 读取操纵杆输入(~50毫秒,精确计时器)
- 发送机器人数据包(~ 20msecs,精确定时器)
- 更新UI的某些方面(~500毫秒,粗定时器)
- 更新机器人启动后经过的时间(~100毫秒,精确计时器)
- 实现一个看门狗(如果1000毫秒没有机器人响应,将应用程序和机器人置于安全状态)
- 注意:看门狗在我们收到机器人的响应包(~20 msecs)时为馈入
对于在性能关键型代码中使用QTimer对象,您有什么建议吗?请注意,我也尝试过使用不同的线程,但它给我带来了更多的问题,因为应用程序不会"同步",从而无法有效地控制我们测试的机器人。
实际上,我似乎低估了Qt的计时器和事件循环性能。在我的系统上,一个事件循环周期的平均时间约为20k纳秒,加上调度排队函数调用的开销,间隔为1毫秒的计时器很少延迟,大多数超时都比一毫秒短几千纳秒。但它是一个高端系统,在嵌入式硬件上可能会更糟糕。
您应该花时间和概要分析您的目标系统和Qt构建,以确定它是否确实可以运行得足够快,并根据这些测量,调整您的时间来补偿系统延迟,以使您的事件更及时地安排。
你一定要让计时器线程尽可能的空闲,因为如果你用IO或者大量的计算阻塞它,你的计时器将不准确。使用专用线程来调度工作,并使用额外的工作线程来完成实际工作。你也可以尝试一下线程优先级。
最坏的情况下,寻找第三方高性能事件循环实现或创建您自己的,也可能是一个更快的信号机制。正如我已经在评论中提到的,Qt的线程间队列信号非常慢,至少与间接函数调用之类的东西相比。
最后但并非最不重要的是,如果您想每N个单位时间执行任务X,那么只有当任务X在您的系统上花费N个或更少的时间时才有可能。您需要考虑每个任务以及并发运行的所有任务。为了获得准确的调度,您应该测量任务X所花费的时间,如果少于它的频率,则在剩余时间内调度下一次执行,否则立即执行。
- Linux的Cpp上的计时器
- 提升 ASIO 无法识别计时器对象
- 提升 asio 并发计时器取消问题与链
- 使用单体计时器的pthread_cond_timedwait有时会比预期晚超时
- 窗口中的微秒计时器
- 计时器是否从另一个线程启动?
- 如何在 c++ 中创建计时器
- Qt按住鼠标按钮和计时器CPP
- QT精确的计时器计时精度
- 每个对象的C++Qt计时器
- 使用 QT 创建器中的计时器更改速度
- Qt中的亚毫秒计时器
- 在Qt中运行计时器5秒
- QT油漆工更新,计时器仅在关闭窗口时更新
- 在Qt中制作倒计时计时器
- Qt在计时器上更改图片
- 在性能关键软件(Qt)中使用计时器
- Windows(也包括OS X、Linux)上Qt中的高分辨率定期计时器
- 在Windows上更改Qt的计时器分辨率
- QT线程:获取QObject::startTimer:计时器无法从另一个线程启动警告