如何在 tkinter 的主循环中处理阻塞调用/while 1-s? ZMQ/Tkinter

How to handle blocking calls / while 1-s, inside a tkinter's mainloop? ZMQ / Tkinter

我正在使用 ZeroMQ,它是一个消息库(大概是异步 I/O),如果你不知道它是什么,你可以认为它类似于 python 中的套接字库,用于消息传递的套接字通常 运行 在一个无限的 while 循环中,带有一个小的睡眠以保持一切凉爽。

我将代码写在一个单独的文件中,并且我有一个基于该代码的单独工作的 GUI,我想集成这两个代码。

但我遇到的问题是我无法放置 while True 或阻塞 socket.recv()tkinter.mainloop().

我想在阻塞的套接字上接收 - 但我可以解决问题的那一部分,zmq 套接字可以被轮询(定期检查我们是否有任何待处理的消息)或者等效地你可以使用 zmq.DONTWAIT 来做同样的事情。

然而,剩下的问题是我需要一个while True,以便不断轮询套接字,比如每隔一毫秒查看我们是否有消息。

如何将 while True 放入 tkinter .mainloop() 中,以便我不断检查该套接字的状态?

我会想象这样的事情:

while True:    
    update_gui()       # contains the mainloop and all GUI code
    check_socket()     # listener socket for incoming traffic
    if work:
        #              # do a work, while GUI will hang for a bit.

我上网查了一下,发现了SO的解决方案,里面说可以使用小部件的After 属性,但我不确定它是如何工作的。如果有人能帮助我,我将不胜感激!

参考代码:

zmq.DONTWAIT 如果您没有任何使我们在循环中前进的未决消息,则会抛出异常。

while 1:
    if socket_listen and int(share_state):
        try:
            msg =  socket_listen.recv_string(zmq.DONTWAIT)
        except:
            pass

    time.sleep(0.01) 

我希望我可以将它放在 .mainloop() 中,并与 GUI 一起在每次迭代时进行检查。

附加信息: 此处轮询等同于:

How do I put a while True inside the tkinter .mainloop() that allows me to check the state of that socket constantly?

不要使用显式 while True-loop 设计此类部分,最好使用 tkinter-native 工具:询问 .after() 不迟于一定时间重新提交呼叫(让其他事情同时发生,但有一定的确定性,您请求的呼叫仍将不迟于被激活"after" 指定的毫秒数)。


我喜欢Tkinter共存事件处理的架构

因此,如果在 Tkinter 的基础上保持有限状态自动机(游戏或 GUI 前端)的整洁,就可以享受传递协调的 ZeroMQ 消息数据的乐趣 "behind" 场景,就在 Tkinter-native 工具的帮助下,因此不需要任何命令式代码。如果您确实需要具有智能工作的 GUI 集成,只需将消息转换为 tkinter-监控变量即可。

aScheduledTaskID = aGuiRelatedOBJECT.after( msecs_to_wait,
                                            aFunc_to_call = None,
                                            *args
                                            )
# -> <_ID_#_>
# ... guarantees a given wait-time + just a one, soloist-call
#     after a delay of at least delay_ms milliseconds.
#     There is no upper limit to how long it will actually take, but
#     your callback-FUN will be called NO SOONER than you requested,
#     and it will be called only once.
#     aFunc_to_call() may "renew" with .after()
#
# .after_cancel( aScheduledTaskID )  # <- <id> CANCELLED from SCHEDULER
#
# .after_idle() ~ SCHEDULE A TASK TO BE CALLED UPON .mainloop() TURNED-IDLE
#
#     aScheduledTaskOnIdleID = aGuiOBJECT.after_idle( aFunc_to_call = None,
#                                                     *args
#                                                     )
# -> <_ID_#_>

以巧妙的方式使用可重复使用的 tkinter 本机基础架构调度程序工具真是太酷了,不是吗?


结语:

( 阻塞 调用? 最好永远不要使用阻塞调用。有人在这里说过阻塞调用吗? :o))


a while True, or a blocking socket.recv() inside tkinter's .mainloop().

好吧,可以将这样的循环放入与 tkinter 本机基础架构调度程序对齐的组件中,但这个想法实际上是一种反模式,可以将事情变成破坏浩劫(不仅是 tkinter,一般来说,在任何事件循环处理程序中,期望任何 "competitive" 事件处理程序循环以某种方式容忍或以和平共存的方式表现有点冒险相邻的意图 - 问题将会出现(无论是直接阻塞还是由于一个人在调度资源或其他类型的 war 时间和资源方面过于占优势)。