我正在执行实时数据处理+显示,并且每 60 秒访问我们的数据库一次。我不想使用
time.sleep()
每 60 秒等待一次,因为它会取消我的控制权(即对变量的 REPL 访问,这不是必需的,但很好)并冻结 matplotlib 图表。
还有其他选择吗?理想情况下,最初会将控制权交给用户,60 秒后,收回控制权,运行一些代码并更新绘图,然后将控制权交还给用户。 (当我说控制时,我指的是 REPL 控制)。
有什么想法吗?
如果您不需要取消用户控制,有一个非常简单的方法可以做到这一点:创建一个
threading.Timer
。
您想要做的是将函数的“延续”(即
time.sleep
之后的所有内容)移至一个单独的函数 my_function
中,然后按如下方式安排它:
threading.Timer(60, my_function).start()
在
my_function
结束时,它会使用完全相同的代码行安排一个新的 Timer
。
Timer
是一个相当笨重的接口和实现,但它内置于 stdlib 中。您可以在 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 相同的线程上运行,并且不会浪费任何不必要的资源。
如果您想退出程序,您必须设置:
curr_thread.daemon = True
Python 中的守护线程在后台运行,与主程序同时运行。它们的显着特点在于其非阻塞性质,允许主程序无需等待完成即可继续运行。
这意味着主线程不会等待守护线程。