python中time.sleep()的替代方案
我正在进行实时数据处理和显示,每60秒就要访问一次我们的数据库。我不想使用 time.sleep()
来等待60秒,因为这样会让我失去控制(主要是无法在REPL环境中访问变量,虽然这不是必须的,但有时候挺方便的),而且会让matplotlib的图表冻结。
有没有其他的办法?理想情况下,我希望有一种方法,最开始可以让用户控制,然后在60秒后接管控制,执行一些代码,更新图表,然后再把控制权交还给用户。(我说的控制权,是指REPL控制)。
有什么想法吗?
1 个回答
如果你不想干扰用户的操作,其实有个很简单的方法:创建一个 threading.Timer
。
你需要做的是把函数中“继续执行”的部分,也就是在 time.sleep
之后的所有内容,放到一个单独的函数 my_function
里,然后像这样安排它:
threading.Timer(60, my_function).start()
在 my_function
的最后,你再安排一个新的 Timer
,用的还是同样的代码。
Timer
的接口和实现有点笨重,但它是标准库里自带的。你可以在 ActiveState 找到一些示例,或者在 PyPI 上找到更好的模块,它们提供的类可以让你在一个线程上运行多个定时器,而不是每个定时器都用一个线程,还能让你安排重复调用,这样就不用一直手动重新安排了等等。不过,如果只是每60秒运行一次,我觉得用 Timer
应该没问题。
有一点要记住:如果后台任务需要处理用户在 REPL 中使用的相同数据,就可能会出现竞争条件。在交互式环境中(特别是在 Python 中,因为有全局解释器锁 GIL),通常可以让用户自己注意不要引发竞争。如果不能,你就需要某种同步机制。
还有一点要注意:如果你在做图形用户界面(GUI)的工作,根据你使用的 GUI(我相信 matplotlib
是可以配置的,但默认是 tkinter
?),你可能无法从后台线程更新 GUI。
不过其实在这种情况下还有更好的解决方案。GUI 程序有一个事件循环,它在某个线程中运行,几乎所有设计的事件循环都有办法在那个线程中安排一个定时器。对于 tkinter
,如果你有 root
对象的句柄,只需调用 root.after(60000, my_function)
,而不是 threading.Timer(60, my_function).start()
,这样就能在和 GUI 同一个线程中运行,而且不会浪费不必要的资源。