Shiny for Python:如何无需循环失效hack实现异步迭代器
解决Py-Shiny异步数据流无需
invalidate_later的更新问题 核心思路
不需要依赖定时失效的hack,Py-Shiny提供了主动触发反应式上下文刷新的底层方法:reactive.get_current_context().invalidate()。在异步迭代器的回调中更新响应式变量后,直接调用这个方法就能立即触发UI更新,不用靠定时轮询。
具体实现步骤
- 在
watch_changes异步函数中,每次调用rval.set(i)更新响应式变量后,调用reactive.get_current_context().invalidate()主动通知Shiny刷新相关的反应式依赖。 - 移除原来
@reactive.Effect里的循环invalidate_later逻辑,因为现在是数据更新时主动触发刷新,而非定时轮询。
示例代码片段
from shiny import reactive, render, App, ui import asyncio class AsyncIteratorDummy: def __init__(self): self.count = 0 async def __aiter__(self): return self async def __anext__(self): await asyncio.sleep(1) self.count += 1 if self.count > 10: raise StopAsyncIteration return f"更新内容 {self.count}" app = App( ui.page_fluid(ui.output_text("async_text")), async def server(input, output, session): rval = reactive.Value("初始内容") async def watch_changes(): async for item in AsyncIteratorDummy(): rval.set(item) # 主动触发反应式上下文刷新 reactive.get_current_context().invalidate() # 启动异步监听任务 asyncio.create_task(watch_changes()) @output @render.text def async_text(): return rval.get() )
原理说明
reactive.get_current_context()获取当前的反应式上下文,调用其invalidate()方法会立即标记该上下文失效,触发所有依赖此上下文的反应式计算(比如async_text渲染函数)重新执行。- 这种方式属于事件驱动的更新,只有当异步数据流产生新数据时才触发刷新,比定时轮询更高效,也避免了不必要的UI更新。
内容的提问来源于stack exchange,提问作者cvmartin
相关产品推荐
相关产品推荐

