Streamlit从入门到精通 系列:
- 翻译: Streamlit从入门到精通 基础控件 一
- 翻译: Streamlit从入门到精通 显示图表Graphs 地图Map 主题Themes 二
- 翻译: Streamlit从入门到精通 构建一个机器学习应用程序 三
- 翻译: Streamlit从入门到精通 部署一个机器学习应用程序 四
- 翻译: Streamlit从入门到精通 高级用法缓存Cache和Session 五
- 翻译: Streamlit从入门到精通六 实战缓存Cache请求数据
1. 控制Cache缓存大小和持续时间
如果您的应用运行时间较长,并且不断缓存函数,您可能会遇到两个问题:
- 由于缓存太大,应用内存不足。
- 缓存中的对象会变得陈旧,例如,因为您缓存了数据库中的旧数据。
您可以使用 ttl
和 max_entries
参数来解决这些问题,这两个参数都可用于缓存装饰器。
1.1 ttl (time-to-live) 参数
ttl
设置缓存函数的生存时间。如果该时间已到,并且再次调用该函数,则应用将丢弃任何旧的缓存值,并且将重新运行该函数。然后,新计算的值将存储在缓存中。此行为对于防止过时的数据(问题 2)和缓存增长过大(问题 1)非常有用。特别是在从数据库或 API 中提取数据时,您应该始终设置 ttl
,这样您就不会使用旧数据。下面是一个示例:
python
@st.cache_data(ttl=3600) # 👈 Cache data for 1 hour (=3600 seconds)
def get_api_data():
data = api.get('https://jsonplaceholder.typicode.com/posts/1')
return data
Tip提示
您还可以使用 timedelta
设置 ttl
值,例如 ttl=datetime.timedelta(hours=1)
1.2 max_entries参数
max_entries
设置缓存中的最大条目数。缓存条目数的上限对于限制内存(问题 1)很有用,尤其是在缓存大型对象时。将新条目添加到完整缓存时,将删除最旧的条目。下面是一个示例:
python
@st.cache_data(max_entries=1000) # 👈 Maximum 1000 entries in the cache
def get_large_array(seed):
np.random.seed(seed)
arr = np.random.rand(100000)
return arr
2. 自定义加载中动画loading spinner
默认情况下,当缓存函数运行时,Streamlit 会在应用程序中显示一个小的加载中动画。您可以使用 show_spinner
参数轻松修改它,该参数可用于两个缓存装饰器:
python
@st.cache_data(show_spinner=False) # 👈 Disable the spinner
def get_api_data():
data = api.get(...)
return data
@st.cache_data(show_spinner="Fetching data from API...") # 👈 Use custom text for spinner
def get_api_data():
data = api.get(...)
return data
3. 排除输入参数
在缓存函数中,所有输入参数都必须是可哈希的。让我们快速解释一下原因和含义。调用该函数时,Streamlit 会查看其参数值以确定它之前是否缓存过。因此,它需要一种可靠的方法来比较函数调用之间的参数值。对于字符串或 int 来说微不足道,但对于任意对象来说却很复杂!Streamlit 使用哈希来解决这个问题。它将参数转换为稳定键并存储该键。在下一次函数调用时,它会再次对参数进行哈希处理,并将其与存储的哈希键进行比较。
不幸的是,并非所有参数都是可哈希的!例如,您可以将不可哈希的数据库连接或 ML 模型传递给缓存的函数。在这种情况下,您可以从缓存中排除输入参数。只需在参数名称前面加上下划线(例如,_param1
),它就不会用于缓存。即使它发生了变化,如果所有其他参数都匹配,Streamlit 也会返回缓存的结果。
python
@st.cache_data
def fetch_data(_db_connection, num_rows): # 👈 Don't hash _db_connection
data = _db_connection.fetch(num_rows)
return data
connection = init_connection()
fetch_data(connection, 10)
但是,如果要缓存采用不可哈希参数的函数,该怎么办?例如,您可能希望缓存一个函数,该函数将 ML 模型作为输入并返回该模型的层名称。由于模型是唯一的输入参数,因此无法将其从缓存中排除。在这种情况下,可以使用 hash_funcs
参数为模型指定自定义哈希函数。
3.1 hash_funcs
参数
如上所述,Streamlit的缓存装饰器对输入参数和缓存函数的签名进行哈希处理,以确定该函数之前是否运行过并存储了返回值("缓存命中")或需要运行("缓存未命中")。Streamlit 的哈希实现无法哈希的输入参数可以通过在其名称前面添加下划线来忽略。但是在极少数情况下,这是不可取的。即您要对 Streamlit 无法哈希的参数进行哈希处理的位置:
- 当 Streamlit 的哈希机制无法对参数进行哈希时,会导致引发
UnhashableParamError
。 - 当您想要覆盖 Streamlit 的参数默认哈希机制时。
4. Static elements静态元素
从版本 1.16.0 开始,缓存函数可以包含 Streamlit 命令!例如,您可以这样做:
python
@st.cache_data
def get_api_data():
data = api.get('https://jsonplaceholder.typicode.com/posts/1')
st.success("Fetched data from API!") # 👈 Show a success message
return data
正如我们所知,Streamlit 仅在之前没有缓存过的情况下才运行此函数。首次运行时,st.success
消息将出现在应用程序中。但随后的运行会发生什么?它仍然出现! Streamlit 意识到缓存函数中有一个 st.
命令,在第一次运行时保存它,并在后续运行时重播它。重放静态元素适用于两种缓存装饰器。
4.1 您还可以使用此功能来缓存 UI 的整个部分:
python
@st.cache_data
def show_data():
st.header("Data analysis")
data = api.get(...)
st.success("Fetched data from API!")
st.write("Here is a plot of the data:")
st.line_chart(data)
st.write("And here is the raw data:")
st.dataframe(data)
参考
https://docs.streamlit.io/library/advanced-features/caching#basic-usage