通过Python进行实时操作

18 投票
6 回答
51024 浏览
提问于 2025-04-16 23:42

我是一名刚入门的Python编程者,最近遇到了一些可能比较复杂的需求。我是一名认知科学家,需要精确地显示刺激和检测按钮按下的情况。有人告诉我,最好的方法是使用实时操作系统,但我对这个完全没有头绪。理想情况下,每次实验时,程序应该实时运行,实验结束后,操作系统可以恢复到不那么严格的状态。大概会有56次实验。我可以从我的Python脚本中实现这个功能吗?

(不过,我其实只需要知道刺激什么时候被显示。使用实时方法可以确保刺激在我想要的时候被显示,这是一种自上而下的方法。另一方面,如果只是记录计算机实际显示刺激的时间更简单的话,我也可以采取一种自下而上的方法。)

6 个回答

4

因为你想要精确到毫秒的时间延迟测量,所以我不建议你在普通电脑上使用任何可能会被时间切片影响的处理方式。无论是用C、Java还是Python,如果程序是在共享时间的模式下运行,那结果怎么能被验证呢?你可能会被要求证明在测量过程中CPU没有打断这个过程,这样才不会影响结果。

听起来你可能需要制作一个专用的设备,里面有一个以已知速度走动的时钟电路,可以测量刺激和反应之间发生的具体滴答次数。这个设备可以通过没有时间限制的软件来控制。也许你应该把这个问题发到电子工程的论坛上。

如果没有专用设备,你就得开发真正的实时软件,这种软件在现代操作系统中是运行在内核里的,不会受到任务切换的影响。这并不容易做到,而且需要花费很多精力去实现。我的猜测是,这可能比你花时间去制作一个可以软件控制的专用设备还要多。

5

从严格的角度来看,Python并不是一种实时语言,因为它有太多的库和功能,不能做到非常快速。如果你使用的是操作系统,而不是嵌入式系统,那么你已经失去了一些真正的实时能力。(当我听到“实时”这个词时,我想到的是VHDL代码在FPGA的电路中流动所需的时间。其他人可能用它来表示“我按下一个按钮,它就立刻有反应,从我这个慢半拍的人类角度来看是瞬间的”。我假设你是用后者的理解来谈论实时。)

你提到的刺激显示和按钮按下检测,我猜是指你有一个实验,比如给一个人展示一张图片,然后让他们点击一个按钮来识别这张图片或者确认他们见过它——可能是为了测试反应速度。除非你担心精确到毫秒(这在与人类反应时间相比应该是微不足道的),你可以用Python来做这样的测试。想要做图形用户界面(GUI),可以看看Tkinter:http://www.pythonware.com/library/tkinter/introduction/。如果想研究刺激和按钮按下之间的时间,可以查看时间文档:http://docs.python.org/library/time.html

祝你好运!

23

当人们谈论实时计算时,他们指的是从一个中断(通常是由定时器触发的)到应用程序处理这个中断的代码运行之间的延迟,这个延迟既要小又要可预测。这意味着控制过程可以在非常精确的时间间隔内重复运行,或者像你提到的那样,外部事件可以被非常精确地计时。延迟的变化通常被称为“抖动”,比如说1毫秒的最大抖动意味着一个中断反复到达时,响应的延迟最多变化1毫秒。

这里的“小”和“可预测”都是相对的。当人们谈论实时性能时,他们可能指的是最大抖动为1微秒(比如说,做电力传输逆变器的人会关注这种性能),也可能指的是最大抖动为几毫秒。这一切都取决于应用的需求。

无论如何,Python可能并不是这个工作的合适工具,原因有几个:

  • Python主要运行在桌面操作系统上。桌面操作系统对最大抖动有一个下限;在Windows上,这个下限是几秒钟。几秒钟的事件并不常见,可能每隔一两天才会发生一次,而如果恰好和你要测量的事件重合,那你就比较倒霉了;但迟早会发生这种情况;几百毫秒的抖动可能每小时就会发生一次,而几十毫秒的抖动则相对频繁。桌面Linux的情况可能类似,不过你可以通过不同的编译选项和补丁集来改善这个情况——可以查查Google的PREEMPT_RT_FULL。
  • Python的“停止世界”垃圾回收机制使得延迟变得不可预测。当Python决定需要运行垃圾回收时,你的程序会被暂停,直到垃圾回收完成。你可能通过仔细的内存管理和设置垃圾回收参数来避免这种情况,但这也取决于你使用的库,有时你可能无法避免。
  • Python的内存管理的其他特性使得确定性延迟变得困难。大多数实时系统避免使用堆分配(比如C语言的malloc或C++的new),因为它们所需的时间是不可预测的。Python巧妙地将这一点隐藏起来,使得控制延迟变得非常困难。同样,使用很多现成的库只会让情况变得更糟。
  • 同样,实时进程必须确保它们的所有内存都保存在物理RAM中,而不是被换出到交换区。在Python中,尤其是在Windows上,没有好的方法来控制这一点(在Linux上,你可能可以在某个地方调用mlockall,但任何新的分配都会打乱这个情况)。

不过我有一个更基本的问题。你没有说明你的按钮是物理按钮还是屏幕上的按钮。如果是屏幕上的按钮,操作系统会在物理鼠标按钮按下和事件到达你的Python应用之间引入不可预测的延迟。你打算如何处理这个问题?没有更准确的测量方法,你又怎么知道这个延迟是否存在呢?

撰写回答