我正在进行实时数据处理+显示,每60秒就会点击一次数据库。我不想每隔60秒使用time.sleep()
,因为它取消了对我的控制(即REPL访问变量,这不是必要但很好)并冻结了matplotlib图表。
还有其他选择吗?理想情况下,最初可以控制用户的东西,60秒后,取消控制,运行一些代码,更新绘图,然后将控制权交还给用户。 (当我说控制时,我指的是REPL控制)。
有什么想法吗?
答案 0 :(得分:7)
如果您不需要取消用户控制,可以使用以下方法:创建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相同的线程上运行,没有浪费任何不必要的资源。