gpt4 book ai didi

python - 在 tkinter 的 Tk.after() 方法中使用 async/await 关键字

转载 作者:太空宇宙 更新时间:2023-11-04 09:45:36 25 4
gpt4 key购买 nike

我正在使用 Python3.5 和 Tkinter 创建一个加密货币交换 API 客户端。我有几个显示器,我想每 10 秒异步更新一次。我可以使用 Tk.after() 每 10 秒更新一次显示,就像在这个例子中一样

def updateLoans():
offers = dd.loanOffers()
demands = dd.loanDemands()
w.LoanOfferView.delete(1.0, END)
w.LoanDemandView.delete(1.0, END)
w.LoanOfferView.insert(END, offers)
w.LoanDemandView.insert(END, demands)
print('loans refreshed')

root.after(10000, updateLoans)

为了让 after 方法继续每 10 秒更新一次,函数 updateLoans() 需要作为可调用函数传递给 after() 在函数内部。

现在让我难过的部分是,当我使这个函数与 python 的新 async 和 await 关键字异步时

async def updateLoans():
offers = await dd.loanOffers()
demands = await dd.loanDemands()
w.LoanOfferView.delete(1.0, END)
w.LoanDemandView.delete(1.0, END)
w.LoanOfferView.insert(END, offers)
w.LoanDemandView.insert(END, demands)
print('loans refreshed')

root.after(10000, updateLoans)

这里的问题是我无法在 after 方法的参数内部等待可调用对象。所以我收到运行时警告。 RuntimeWarning:从未等待协程“updateLoans”

我的初始函数调用放在事件循环中。

loop = asyncio.get_event_loop()
loop.run_until_complete(updateLoans())
loop.close()

最初显示效果很好,但从不更新。

如何使用 Tk.after 异步持续更新 tkinter 显示?

最佳答案

tk.after 接受普通函数,而不是协程。要运行协程直至完成,您可以使用 run_until_complete,就像您第一次做的那样:

loop = asyncio.get_event_loop()
root.after(10000, lambda: loop.run_until_complete(updateLoans()))

此外,不要调用 loop.close(),因为您将再次需要循环。


上述快速修复适用于许多用例。然而,事实是,如果 updateLoans() 由于网络速度慢或远程服务问题而花费很长时间,它将导致 GUI 完全无响应。一个好的 GUI 应用程序会希望避免这种情况。

虽然 Tkinter 和 asyncio cannot share an event loop yet ,完全有可能在单独的线程中运行 asyncio 事件循环。然后主线程运行 GUI,而专用的异步线程运行所有异步协程。当事件循环需要通知 GUI 刷新某些东西时,它可以使用队列 as shown here .另一方面,如果 GUI 需要告诉事件循环做某事,它可以调用 call_soon_threadsafe or run_coroutine_threadsafe。 .

示例代码(未经测试):

gui_queue = queue.Queue()

async def updateLoans():
while True:
offers = await dd.loanOffers()
demands = await dd.loanDemands()
print('loans obtained')
gui_queue.put(lambda: updateLoansGui(offers, demands))
await asyncio.sleep(10)

def updateLoansGui(offers, demands):
w.LoanOfferView.delete(1.0, END)
w.LoanDemandView.delete(1.0, END)
w.LoanOfferView.insert(END, offers)
w.LoanDemandView.insert(END, demands)
print('loans GUI refreshed')

# http://effbot.org/zone/tkinter-threads.htm
def periodicGuiUpdate():
while True:
try:
fn = gui_queue.get_nowait()
except queue.Empty:
break
fn()
root.after(100, periodicGuiUpdate)

# Run the asyncio event loop in a worker thread.
def start_loop():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.create_task(updateLoans())
loop.run_forever()
threading.Thread(target=start_loop).start()

# Run the GUI main loop in the main thread.
periodicGuiUpdate()
root.mainloop()

# To stop the event loop, call loop.call_soon_threadsafe(loop.stop).
# To start a coroutine from the GUI, call asyncio.run_coroutine_threadsafe.

关于python - 在 tkinter 的 Tk.after() 方法中使用 async/await 关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49958180/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com