如何在async def上下文外调用asyncio.Event.set()?解决按钮点击阻塞问题
问题修正方案
问题根源
你的代码中asyncio.run(waiter(event1))会启动独立的asyncio事件循环并阻塞主线程,直到waiter协程执行完毕。而ipywidgets的按钮点击事件依赖主线程的UI事件循环处理,主线程被阻塞后,点击操作的回调函数根本无法执行,自然无法触发event1.set()。
另外,event_done是异步函数,但ipywidgets的on_click期望传入同步回调,直接传入异步函数不会被正确调度执行。
修正后的代码
import asyncio from ipywidgets import Button def event_done(btn): event1.set() print('registred a click') run_button = Button(description='continue') run_button.on_click(event_done) event1 = asyncio.Event() async def waiter(event1): print('waiting') await event1.wait() print("After waiting") display(run_button) await waiter(event1)
关键修改点
- 替换
asyncio.run为直接await:Jupyter环境本身已经运行着一个asyncio事件循环,直接await waiter(event1)不会阻塞主线程,UI事件可以正常响应。 - 将异步回调改为同步函数:
event.set()是同步操作,不需要异步回调,直接用普通函数作为按钮点击的处理逻辑即可。如果确实需要在回调中执行异步操作,可以用asyncio.create_task()包装异步代码,示例如下:def event_done(btn): asyncio.create_task(async_set_event()) async def async_set_event(): await asyncio.sleep(0.1) # 模拟异步操作 event1.set() print('registred a click')
内容的提问来源于stack exchange,提问作者David Streuli
相关产品推荐
相关产品推荐

