DLW*_*DLW 7 python python-asyncio streamlit
目标是在后台提取实时数据(例如每 5 秒)并在需要时提取到仪表板。这是我的代码。它有点工作,但我看到两个问题: 1.如果我将 st.write("TESTING!") 移到最后,由于 while 循环,它永远不会被执行。有办法改进吗?我可以想象,随着仪表板的增长,将会有多个页面/表格等。这不会提供太多的灵活性。2. async 函数中的 return px 行,我对此不太满意,因为我通过反复试验得到了正确的结果。抱歉,我是个新手,但如果有更好的方法,我将非常感激。
谢谢你!
import asyncio
import streamlit as st
import numpy as np
st.set_page_config(layout="wide")
async def data_generator(test):
while True:
with test:
px = np.random.randn(5, 1)
await asyncio.sleep(1)
return px
test = st.empty()
st.write("TESTING!")
with test:
while True:
px = asyncio.run(data_generator(test))
st.write(px[0])
Run Code Online (Sandbox Code Playgroud)
根据我的经验,使用 asyncio 的技巧是提前创建布局,在需要显示异步信息的地方使用空小部件。异步协程将接收这些空槽并填充它们。这应该可以帮助您创建更复杂的应用程序。
然后 asyncio.run 命令可以成为最后执行的 Streamlit 操作。正如您所观察到的,此后的任何 Streamlit 命令都不会被处理。
我还建议在初始布局期间在异步函数之外安排任何输入小部件,然后发送小部件输出进行处理。当然,您可以在函数内绘制输入小部件,但布局可能会变得很棘手。
如果您仍然希望将输入小部件放在异步函数中,那么您肯定必须将它们放在 while 循环之外,否则您会收到重复的小部件错误。(您可能会尝试通过始终创建新的小部件来克服这个问题,但是输入小部件将被“重置”并且无法实现交互,更不用说可能的内存问题了。)
这是我的意思的完整示例:
import asyncio
import pandas as pd
import plotly.express as px
import streamlit as st
from datetime import datetime
CHOICES = [1, 2, 3]
def main():
print('\nmain...')
# layout your app beforehand, with st.empty
# for the widgets that the async function would populate
graph = st.empty()
radio = st.radio('Choose', CHOICES, horizontal=True)
table = st.empty()
try:
# async run the draw function, sending in all the
# widgets it needs to use/populate
asyncio.run(draw_async(radio, graph, table))
except Exception as e:
print(f'error...{type(e)}')
raise
finally:
# some additional code to handle user clicking stop
print('finally')
# this doesn't actually get called, I think :(
table.write('User clicked stop!')
async def draw_async(choice, graph, table):
# must send in all the streamlit widgets that
# this fn would interact with...
# this could possibly work, but layout is tricky
# choice2 = st.radio('Choose 2', CHOICES)
while True:
# this would not work because you'd be creating duplicated
# radio widgets
# choice3 = st.radio('Choose 3', CHOICES)
timestamp = datetime.now()
sec = timestamp.second
graph_df = pd.DataFrame({
'x': [0, 1, 2],
'y': [max(CHOICES), choice, choice*sec/60.0],
'color': ['max', 'current', 'ticking']
})
df = pd.DataFrame({
'choice': CHOICES,
'current_choice': len(CHOICES)*[choice],
'time': len(CHOICES)*[timestamp]
})
graph.plotly_chart(px.bar(graph_df, x='x', y='y', color='color'))
table.dataframe(df)
_ = await asyncio.sleep(1)
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)