Advanced concepts of Streamlit
既然你已经了解了Streamlit应用程序如何运行和处理数据,现在让我们来谈谈如何提高效率。缓存允许你保存函数的输出,以便在重新运行时可以跳过它。会话状态允许你为每个用户保存信息,这些信息在重新运行之间保持不变。这不仅可以帮助你避免不必要的重新计算,还可以让你创建动态页面并处理渐进式过程。
Caching
缓存可以让您的应用程序在从网络加载数据、操作大型数据集或执行昂贵的计算时保持高性能。
缓存的基本思想是存储昂贵函数调用的结果,并在相同的输入再次出现时返回缓存的结果。这避免了使用相同输入值重复执行函数。
要在 Streamlit 中缓存一个函数,你需要为其应用一个缓存装饰器。你有两种选择:
st.cache_data
是推荐用于缓存返回数据的计算的方式。当你使用一个返回可序列化数据对象(例如 str、int、float、DataFrame、dict、list)的函数时,使用st.cache_data
。它在每次函数调用时创建数据的新副本,使其免受突变和竞争条件的影响。st.cache_data
的行为在大多数情况下是你想要的——所以如果你不确定,从st.cache_data
开始,看看它是否有效!st.cache_resource
是推荐用于缓存全局资源(如机器学习模型或数据库连接)的方式。当你的函数返回不可序列化的对象且你不想多次加载时,使用st.cache_resource
。它返回缓存的对象本身,该对象在所有重新运行和会话之间共享,无需复制或重复。如果你修改了使用st.cache_resource
缓存的对象,该修改将在所有重新运行和会话中存在。
示例:
@st.cache_data
def long_running_function(param1, param2):
return …
在上面的例子中,long_running_function
被 @st.cache_data
装饰。因此,Streamlit 记录了以下内容:
- 函数的名称 (
"long_running_function"
)。 - 输入的值(
param1
,param2
)。 - 函数内的代码。
在运行long_running_function
中的代码之前,Streamlit会检查其缓存中是否有之前保存的结果。如果它找到给定函数和输入值的缓存结果,它将返回该缓存结果,而不会重新运行函数的代码。否则,Streamlit会执行该函数,将结果保存在其缓存中,并继续脚本的运行。在开发过程中,缓存会随着函数代码的变化自动更新,确保缓存中反映最新的更改。

Streamlit的两个缓存装饰器及其使用案例。
有关Streamlit缓存装饰器、其配置参数及其限制的更多信息,请参阅Caching。
Session State
会话状态提供了一个类似字典的接口,您可以在其中保存脚本重新运行之间保留的信息。使用st.session_state
与键或属性表示法来存储和调用值。例如,st.session_state["my_key"]
或st.session_state.my_key
。请记住,小部件会自行处理其状态,因此您并不总是需要使用会话状态!
What is a session?
会话是查看应用程序的单个实例。如果您从浏览器的两个不同标签页查看应用程序,每个标签页将拥有自己的会话。因此,应用程序的每个查看者都将有一个与其特定视图相关联的会话状态。当用户与应用程序交互时,Streamlit 会维护此会话。如果用户刷新浏览器页面或重新加载应用程序的URL,他们的会话状态将重置,并重新开始一个新的会话。
Examples of using Session State
这是一个简单的应用程序,用于计算页面运行的次数。每次点击按钮时,脚本将重新运行。
import streamlit as st
if "counter" not in st.session_state:
st.session_state.counter = 0
st.session_state.counter += 1
st.header(f"This page has run {st.session_state.counter} times.")
st.button("Run it again")
-
首次运行: 应用程序首次为每个用户运行时,会话状态为空。因此,创建了一个键值对(
"counter":0
)。随着脚本的继续,计数器立即增加("counter":1
),并显示结果:“此页面已运行1次。”当页面完全渲染后,脚本完成,Streamlit服务器等待用户进行操作。当用户点击按钮时,重新运行开始。 -
第二次运行: 由于 "counter" 已经是会话状态中的一个键,它不会被重新初始化。随着脚本的继续执行,计数器增加(
"counter":2
),结果显示为:"此页面已运行 2 次。"
有几个常见的场景中,会话状态(Session State)非常有用。如上所示,当您有一个逐步进行的过程,并希望在一次重新运行到下一次之间建立起来时,会话状态就会被使用。会话状态也可以用于防止重新计算,类似于缓存。然而,它们之间的差异很重要:
- 缓存将存储的值与特定的函数和输入关联起来。所有用户在所有会话中都可以访问缓存的值。
- 会话状态将存储的值与键(字符串)关联。会话状态中的值仅在保存它的单个会话中可用。
如果你的应用程序中有随机数生成功能,你可能会使用会话状态。这里有一个例子,数据在每个会话开始时随机生成。通过将这些随机信息保存在会话状态中,每个用户打开应用程序时会得到不同的随机数据,但在他们与应用程序交互时,数据不会不断变化。如果你使用选择器选择不同的颜色,你会看到数据不会在每次重新运行时重新随机化。(如果你在新标签页中打开应用程序以开始新会话,你会看到不同的数据!)
import streamlit as st
import pandas as pd
import numpy as np
if "df" not in st.session_state:
st.session_state.df = pd.DataFrame(np.random.randn(20, 2), columns=["x", "y"])
st.header("Choose a datapoint color")
color = st.color_picker("Color", "#FF0000")
st.divider()
st.scatter_chart(st.session_state.df, x="x", y="y", color=color)
如果您为所有用户提取相同的数据,您可能会缓存一个检索该数据的函数。另一方面,如果您提取特定于用户的数据,例如查询他们的个人信息,您可能希望将其保存在会话状态中。这样,查询的数据仅在该会话中可用。
正如基本概念中提到的,会话状态也与小部件相关。小部件非常神奇,它们会默默地处理状态。然而,作为一个高级功能,您可以通过为小部件分配键来在代码中操作它们的值。分配给小部件的任何键都会成为会话状态中的一个键,该键与小部件的值相关联。这可以用来操作小部件。在您理解Streamlit的基础知识后,如果您感兴趣,可以查看我们的小部件行为指南以深入了解细节。
Connections
如上所述,你可以使用@st.cache_resource
来缓存连接。这是最通用的解决方案,允许你使用几乎任何Python库中的连接。然而,Streamlit还提供了一种便捷的方式来处理一些最流行的连接,比如SQL!st.connection
为你处理了缓存,因此你可以享受更少的代码行数。从数据库中获取数据可以像这样简单:
import streamlit as st
conn = st.connection("my_database")
df = conn.query("select * from my_table")
st.dataframe(df)
当然,您可能想知道您的用户名和密码放在哪里。Streamlit 提供了一个方便的机制用于Secrets management。现在,让我们看看st.connection
如何很好地与secrets配合使用。在您的本地项目目录中,您可以保存一个.streamlit/secrets.toml
文件。您可以将您的secrets保存在toml文件中,st.connection
就会使用它们!例如,如果您有一个应用文件streamlit_app.py
,您的项目目录可能看起来像这样:
your-LOCAL-repository/
├── .streamlit/
│ └── secrets.toml # Make sure to gitignore this!
└── streamlit_app.py
对于上面的SQL示例,你的secrets.toml
文件可能如下所示:
[connections.my_database]
type="sql"
dialect="mysql"
username="xxx"
password="xxx"
host="example.com" # IP or URL
port=3306 # Port number
database="mydb" # Database name
由于您不希望将secrets.toml
文件提交到您的存储库中,因此在准备发布应用程序时,您需要了解您的主机如何处理机密信息。每个主机平台可能有不同的方式来传递您的机密信息。例如,如果您使用Streamlit Community Cloud,每个部署的应用程序都有一个设置菜单,您可以在其中加载您的机密信息。在编写完应用程序并准备部署后,您可以阅读有关如何在Community Cloud上部署您的应用程序的所有信息。
还有问题吗?
我们的 论坛 充满了有用的信息和Streamlit专家。