Tkinter GUI、I/O 和线程:何时使用队列,何时使用事件?

我正在使用 TKinter 构建一个 GUI(用于与多通道分析仪的套接字连接)以定期(~15 秒)接收和绘制数据(~15.000.000 值)。

在接收数据时,我不希望 GUI 冻结,所以我使用多线程进行连接处理、数据接收和绘图操作。正如在可重现的代码中看到的那样,我通过设置一个事件并threading.Event()一个接一个地处理线程(initSettings()&中的几行代码acquireAndPlotData)来实现这一点。我唯一一次干扰 GUI 是在绘制到画布时 & 我使用 tkintersafter()方法执行此操作。

启动时,只要窗口打开并按预期工作,代码就会运行而不会冻结并接收和绘图。

当我读到在 tkinter GUI 中处理阻塞 I/O 操作时,我只找到了递归排队和检查队列的示例(使用Queueafter(), 1 2 3 4 5 ),但我发现它更方便,更容易处理这些操作threading.Event()

现在我的问题是:

我是在使用正确的方法还是在这里遗漏了一些重要的东西?(关于线程安全,竞争条件,如果绘图失败并且花费的时间比数据采集时间长怎么办?我没有想到的东西?不良做法?等等......)

我将非常感谢您对此事的反馈!


繁花如伊
浏览 126回答 1
1回答

波斯汪

所以我这样做了,但我不知道它是否适合你,或者这是否是一个很好的方法,但它可以像评论中所述那样保护你,它的好处是.after你的函数do_stuff只在需要时被调用.import tkinter as tkimport timeimport threadingdef get_data():    time.sleep(3)    print('sleeped 3')    _check.set(1)def do_stuff():    try:        root.configure(bg='#'+str(_var.get()))        _var.set(_var.get()+101010)    except:        _var.set(101010)root = tk.Tk()_check = tk.IntVar(value=0)_var = tk.IntVar(value=101010)def callback(event=None, *args):    t1 = threading.Thread(target=get_data)    t1.start()        do_stuff()    _check.trace_add('write', callback) #kepp track of that variable and trigger callback if changedcallback() # start the looproot.mainloop()一些研究:interpreter 仅在创建它的线程中有效,所有 Tk 活动也必须在该线程中发生。这意味着必须在创建解释器的线程中调用主循环。可以从其他线程调用命令;_tkinter 将为解释器线程排队一个事件,然后解释器线程将执行命令并传回结果。#l1493 var_invoke The current thread is not the interpreter thread.  Marshal        the call to the interpreter thread, then wait for        completion. */    if (!WaitForMainloop(self))                return NULL;在 python 线程中使用 intvar-doublevar 是否安全当您设置一个变量时,它会在与该变量关联的主控件上调用 globalsetvar 方法。_tk.globalsetvar 方法在 C 中实现,并在内部调用 var_invoke,后者在内部调用 WaitForMainLoop,它将尝试安排命令在主线程中执行,如我上面引用的 _tkinter 源中所述。     Start       |       |<----------------------------------------------------------+       v                                                           ^   Do I have    No[*]  Calculate how            Sleep for at       |   work to do?  -----> long I may sleep  -----> most that much --->|       |                                        time               |       | Yes                                                       |       |                                                           |       v                                                           |   Do one callback                                                 |       |                                                           |       +-----------------------------------------------------------+常识来自错误追踪器:Tkinter 和线程。如果你想同时使用 tkinter 和线程,最安全的方法是在主线程中进行所有 tkinter 调用。如果工作线程生成 tkinter 调用所需的数据,请使用 queue.Queue 将数据发送到主线程。为了彻底关闭,添加一个方法来等待线程停止并在按下窗口关闭按钮 [X] 时调用它。效果机器人只需在主线程中运行所有 UI 代码,让编写器写入一个 Queue 对象;例如结论你做事的方式和我做事的方式似乎很理想,但它们似乎一点也没错。这取决于需要什么。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python