Streamlit性能優化:緩存與狀態管理實戰

目錄

📌?核心特性

📌 運行原理

(1)全腳本執行

(2)差異更新

📌 緩存機制

?為什么使用緩存?

使用@st.cache_data的優化方案

緩存適用場景

使用st.session_state的優化方案

📌總結


Streamlit 是一個開源的 Python 庫,專為快速構建數據科學和機器學習 Web 應用而設計。它無需前端開發經驗,通過簡單 API 即可創建交互式界面,適合原型開發和數據展示

Streamlit官方地址:Streamlit ? A faster way to build and share data apps

📌?核心特性

  1. 極簡代碼:用純 Python 實現界面交互
  2. 實時預覽:保存代碼后自動刷新頁面
  3. 豐富組件:支持圖表、表格、滑塊、文件上傳等
  4. 無縫集成:兼容 Pandas、Matplotlib、PyTorch 等主流庫

安裝Streamlit

pip3 install streamlit

先通過一個簡單的Hello World案例來了解Streamlit

import streamlit as st# 顯示標題
st.title("Hello World,I'm echola")# 顯示文本
st.write("這是一個由Streamlit搭建的Web平臺")

運行:

 streamlit run hello.py

結果:

?是不是很強悍,三行代碼搞定一個Web應用

📌 運行原理

Streamlit 的運行邏輯圍繞腳本的線性執行響應式更新展開,其核心設計是讓開發者以極簡的方式構建交互式應用。以下是關鍵邏輯分步解析:

1、啟動Web服務器

  • ?Streamlit 啟動一個本地 Web 服務器,默認監聽 8501 端口
  • 打開瀏覽器并導航到 http://localhost:8501,展示應用界面

2、解析和執行腳本:

  • Streamlit 解析 hello.py 文件,生成抽象語法樹(AST)
  • 動態執行腳本中的代碼,按照順序執行每個 Streamlit 組件(如 st.title 和 st.write)

3、組件渲染

  • 每個 Streamlit 組件(如 st.title st.write)會被注冊到當前頁面的狀態中
  • 頁面會根據組件的順序和內容進行渲染

4、實時更新:

  • 基于Websocket通信:瀏覽器與服務器保持長連接,腳本輸出的文本、圖表等實時推送至前端
  • 增量更新機制:Streamlit只能對比前后兩次執行的輸出差異,僅向瀏覽器發送差異部分,也就是只更新變化的部分(而非刷新整個頁面),Streamlit 會自動重新運行政整個腳本(而非局部更新)并更新頁面,確保了開發過程中的高效性和實時性

上述增量更新可能會有一點矛盾,簡而言之就是,「全腳本執行 + 差異更新」的設計,讓 Streamlit 在開發便捷性(無需手動管理更新)和運行效率(局部渲染)之間取得了完美平衡

(1)全腳本執行

??:也要避免全局作用域的冗余計算(需用緩存優化)

下來使用一個簡單的案例,來模擬Streamlit加載全腳本的耗時過程

import time
import streamlit as st# 全腳本執行部分:以下代碼每次交互都會運行
st.title("TimeOut Example")  # ? 標題會重復渲染,但 Streamlit 會優化為"增量更新"# 局部增量執行:以下代碼僅在按鈕點擊時觸發
if st.button("Click me"):processing_bar = st.progress(0)  # 每次點擊時新建進度條with st.spinner("Loading..."):for percent_complete in range(100):time.sleep(0.05)processing_bar.progress(percent_complete + 1)st.success("Loading completed!")

?當用戶點擊按鈕時,觸發 if 條件判斷,顯示加載提示框 "Loading..."。開始模擬耗時操作,通過循環和 time.sleep 模擬耗時。每次循環中,更新進度條的值,進度條從0%逐漸增加到100%

直至耗時完成5s后,隱藏加載提示框,顯示成功消息框”Loading completed“

再次點擊【Click me】,?重復上述效果圖

可以從上述效果中看出,無論是頁面首次加載、按鈕點擊,還是其他組件交互(如下拉框選擇),Streamlit都會從頭到尾重新執行整個腳本

雖然腳本會全量執行,但Streamlit內部通過智能的組件狀態管理和緩存機制,只更頁面中發生變化的部分(如按鈕觸發的進度條),而不是刷新整個頁面

接下來會使用緩存機制進行優化?

(2)差異更新

?可以高效渲染(減少網絡傳輸數據量和瀏覽器渲染開銷)和無縫體驗(用戶輸入狀態,如:文本框焦點、滾動條位置,不會因為局部更新而丟失)

??:也要關注復雜UI的組件鍵(Key)的穩定性

📌 緩存機制

?為什么使用緩存?

🔴 問題:每次點擊click按鈕時,代碼會從執行整個耗時操作(for循環+time.sleep),即使操作結果不變

🥀 緩存的作用:將耗時操作的結果緩存起來,后續重復調用時直接讀取緩存,避免重復計算

解決重復計算問題:通過裝飾器@st.cache_data(緩存數據)或@st.cache_resource(緩存資源如模型、數據庫連接),避免腳本執行導致的重復計算

@st.cache_data
def heavy_computation():# 此函數僅在輸入參數或代碼變更時重新執行return result

使用@st.cache_data的優化方案

那優化一下上面提到的問題

import time
import streamlit as stst.title("Optimize Example")# 緩存耗時操作的結束(假設操作是無參數)
@st.cache_data
def expensive_operation():# 模擬耗時操作(例如:數據計算)result = []for _ in range(100):time.sleep(0.05)  # 假設這是實際的計算步驟result.append(_)  # 模擬中間結果return resultif st.button("Click me"):processing_bar = st.progress(0)  # 每次點擊時新建進度條with st.spinner("Loading..."):# 獲取數據(首次點擊執行耗時操作,后續點擊直接讀緩存)data = expensive_operation()for percent_complete in range(len(data)):processing_bar.progress(percent_complete + 1)st.success("Loading completed!")

首次點擊【Click me】,會出現

大概5s后,執行完成

?重復點擊【Click me】?,不會重復加載進度條,由于直接讀取緩存結果,無需重復計算,數據已緩存,進度條會快速更新到100%

通過 @st.cache_data 裝飾器緩存耗時操作的結果,避免每次點擊按鈕時都重新執行耗時操作

不是所有耗時操作都必須使用緩存

緩存適用場景

  • 需要緩存的場景
    • 耗時操作的結果是?靜態的(例如讀取文件、初始化模型、復雜計算)。
    • 操作結果?不依賴外部變量或用戶輸入
  • 不適用緩存場景
    • 操作結果?依賴動態參數(例如用戶輸入的變量),此時需通過函數參數觸發緩存更新。
    • 操作需要?實時更新(例如每次點擊都需重新計算)

如果耗時操作?依賴參數,可以通過函數參數控制緩存版本:

@st.cache_data
def expensive_operation(param1, param2):# 根據參數執行不同計算results = []for _ in range(100):time.sleep(0.05)results.append(param1 + param2 + _)return results# 在按鈕點擊時傳入參數
data = expensive_operation(10, 20)  # 參數不同會生成不同緩存

可以看出:

  • 緩存機制:通過?@st.cache_data?緩存靜態計算結果,減少重復執行。
  • 進度條優化:將耗時操作與進度條更新分離,首次加載緩存后,后續交互可快速完成

那上述代碼就沒有什么問題了嗎?

??接下來分析原代碼存在的弊端:

  1. 進度條重復創建:每次點擊按鈕都會新建processing_bar,導致多次點擊時進度條堆疊
  2. 無法阻止重復提交:在耗時操作執行期間,用戶仍可多次點擊按鈕,導致邏輯混亂
  3. 狀態丟失:進度完成后的狀態(如success提示)無法持久化

使用st.session_state的優化方案

1、保存進度條實例

if "processing_bar" not in st.session_state:st.session_state.processing_bar = None  # 初始化進度條容器if st.button("Click me"):# 僅在第一次點擊時創建進度條if not st.session_state.processing_bar:st.session_state.processing_bar = st.progress(0)# 后續操作復用已有進度條with st.spinner("Loading..."):data = expensive_operation()for i in range(len(data)):st.session_state.processing_bar.progress(i + 1)# 完成后清空引用st.session_state.processing_bar = Nonest.success("Done!")

2. 防止重復提交

if "is_processing" not in st.session_state:st.session_state.is_processing = False  # 狀態鎖if st.button("Click me") and not st.session_state.is_processing:st.session_state.is_processing = True  # 鎖定try:# 執行耗時操作...finally:st.session_state.is_processing = False  # 釋放

3. 持久化完成狀態

if "load_complete" not in st.session_state:st.session_state.load_complete = Falseif st.button("Click me"):# 執行操作...st.session_state.load_complete = Trueif st.session_state.load_complete:st.success("數據已加載完成!")st.balloons()  # 顯示動畫效果

?完整優化代碼

import time
import streamlit as stst.title("Optimized Example")# 初始化會話狀態
if "processing_bar" not in st.session_state:st.session_state.processing_bar = None
if "is_processing" not in st.session_state:st.session_state.is_processing = False
if "load_complete" not in st.session_state:st.session_state.load_complete = False@st.cache_data
def expensive_operation():result = []for _ in range(100):time.sleep(0.05)result.append(_)return resultif st.button("Click me") and not st.session_state.is_processing:st.session_state.is_processing = Truetry:# 創建或復用進度條if not st.session_state.processing_bar:st.session_state.processing_bar = st.progress(0)with st.spinner("Loading..."):data = expensive_operation()for i in range(len(data)):st.session_state.processing_bar.progress(i + 1)st.session_state.load_complete = Truefinally:st.session_state.is_processing = Falsest.session_state.processing_bar = None  # 重置進度條if st.session_state.load_complete:st.success("操作成功!")st.balloons()

關鍵作用總結

會話狀態項功能說明
processing_bar保持進度條對象引用,防止重復創建
is_processing實現類似互斥鎖,防止重復提交
load_complete持久化完成狀態,實現跨腳本執行記憶

通過?st.session_state?實現了:

  1. 狀態持久化:在 Streamlit 的全腳本重執行機制中保持關鍵狀態
  2. 資源管理:避免 DOM 元素重復創建
  3. 交互安全:防止用戶誤操作導致的邏輯沖突

?這種模式特別適合需要保持復雜交互狀態的場景(如多步驟表單、長任務處理)

📌總結

通過?緩存機制?減少重復計算,結合?st.session_state?管理會話狀態,Streamlit 可以高效處理復雜交互場景,同時保持代碼簡潔和用戶體驗流暢。這種優化策略尤其適合需要頻繁交互、狀態保持或耗時操作的 Web 應用開發?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901155.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901155.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901155.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

十七、TCP編程

TCP 編程是網絡通信的核心,其 API 圍繞面向連接的特性設計,涵蓋服務端和客戶端的交互流程。以下是基于 ?C 語言的 TCP 編程核心 API 及使用流程的詳細解析: 核心 API 概覽 ?函數?角色?描述socket()通用創建套接字,指定協議族…

將外網下載的 Docker 鏡像拷貝到內網運行

將外網下載的 Docker 鏡像拷貝到內網運行,可以通過以下步驟實現: 一、在有外網訪問權限的機器上操作 下載鏡像 使用docker pull命令下載所需的鏡像。例如,如果你需要下載一個名為nginx的鏡像,可以運行以下命令:docke…

《深入理解生命周期與作用域:以C語言為例》

🚀個人主頁:BabyZZの秘密日記 📖收入專欄:C語言 🌍文章目入 一、生命周期:變量的存在時間(一)生命周期的定義(二)C語言中的生命周期類型(三&#…

Hqst的超薄千兆變壓器HM82409S在Unitree宇樹Go2智能機器狗的應用

本期拆解帶來的是宇樹科技推出的Go2智能機器狗,這款機器狗采用狗身體形態,前端設有激光雷達,攝像頭和照明燈。在腿部設有12個鋁合金精密關節電機,并配有足端力傳感器,通過關節運動模擬狗的運動,并可做出多種…

壹起航:15年深耕,引領中國工廠出海新征程

在全球化浪潮洶涌澎湃的當下,中國工廠正以前所未有的熱情和決心,將目光投向廣闊的海外市場。然而,出海之路并非一帆風順,建立品牌、獲取穩定詢盤、降低營銷成本等難題,如同橫亙在企業面前的高山,阻礙著他們…

【差分隱私相關概念】基礎合成定理和高級合成技術簡單關系

差分隱私中的合成定理用于分析多個機制組合時的隱私損失。基礎合成定理和高級合成技術分別在不同場景下提供了隱私預算增長的估計,其關系如下: 基礎合成定理(線性增長) 機制組合:當k個滿足(ε, δ)-DP的機制按順序組…

【異常處理】Clion IDE中cmake時頭文件找不到 頭文件飄紅

如圖所示是我的clion項目目錄 我自定義的data_structure.h和func_declaration.h在unit_test.c中無法檢索到 cmakelists.txt配置文件如下所示: cmake_minimum_required(VERSION 3.30) project(noc C) #設置頭文件的目錄 include_directories(${CMAKE_SOURCE_DIR}/…

MOS的驅動電流怎么計算?

一、MOS 驅動電流的計算方法 MOS 管在開關時,驅動電路主要是給柵極充放電。柵極電流 不是用來維持電流,而是用來克服電容的充放電需求,尤其是總柵極電荷 Qg。 驅動電流估算公式如下: I_drive Qg f_sw(Qg&#xff…

GGML源碼逐行調試(下)

目錄 前言1. 簡述2. 預分配計算圖內存2.1 創建圖內存分配器2.2 構建最壞情況的計算圖2.3 預留計算圖內存 3. 分詞4. 模型推理與生成4.1 模型推理4.2 采樣 結語下載鏈接參考 前言 學習 UP 主 比飛鳥貴重的多_HKL 的 GGML源碼逐行調試 視頻,記錄下個人學習筆記&#x…

1.5-APP的架構\微信小程序的架構

1.5-APP的架構\微信小程序的架構 APP的三種開發架構: 原生態APP類型 APP-開發架構-原生態-IDEA 演示:remusic項目源碼 NP管理器: http://normalplayer.top/ HttpCanary:https://github.com/mingww64/HttpCanary-SSL-Magisk 安全影…

用css畫一條弧線

ui里有一條弧線,現在用css實現 關鍵代碼 border-bottom-left-radius: 100% 7px 兩個參數分別代表橫向和縱向的深度border-bottom-right-radius: 100% 7px

MSCKF及可觀性總結

可觀性 參考鏈接 真實VIO系統不能觀的維度是4(位置和yaw角),由于EKF的轉移和觀測Jacobian矩陣的線性化點不同、不可觀方向噪聲的存在,實際MSCKF不能觀的維度變成了3,繞重力軸的旋轉(yaw角)被錯…

【Hotspot虛擬機創建對象的過程是什么樣的?】

1. 類加載檢查 觸發條件:當遇到 new 指令時,JVM首先檢查該指令的參數(類符號引用)是否已在常量池中。檢查內容: 類是否已被加載、解析和初始化。若未加載,則觸發類加載過程(加載 → 驗證 → 準…

南墻WAF非標端口防護實戰解析——指定端口安全策略深度剖析

本文系統解析非標端口DDoS攻擊防護難點,重點闡述南墻WAF在指定端口防御中的技術突破。通過某金融機構真實攻防案例,結合Gartner最新防御架構模型,揭示如何構建基于智能流量建模的精準防護體系,為金融、政務等關鍵領域提供可落地的…

Context的全面解析:在不同技術應用中的通用作用與差異

Context的全面解析:在不同技術應用中的通用作用與差異 引言: 在軟件開發中,“Context”這個概念被廣泛使用。它不僅限于某個特定的技術或編程語言,實際上,Context 作為一種抽象的設計模式,貫穿在許多開發領…

尋找峰值 --- 二分查找

目錄 一:題目 二:算法原理 三:代碼實現 一:題目 題目鏈接:162. 尋找峰值 - 力扣(LeetCode) 二:算法原理 三:代碼實現 class Solution { public:int findPeakElemen…

基礎算法訓練7

目錄 庫存管理II 翻轉對 合并K個升序鏈表 存在重復元素II 字符串相乘 字符串解碼 在每個樹行中找最大值 數據流的中位數 被包圍的區域 為高爾夫比賽砍樹 庫存管理II LCR 159. 庫存管理 III - 力扣(LeetCode) 解法一:先進行排序&a…

從單機版到超級APP:MCP如何解鎖AI的超能力

MCP:AI界的“萬能充電寶”——讓AI從此告別“語言不通”的尷尬! 開篇:AI咖啡館的尷尬日常 想象一下這樣的場景: 一位AI助手在咖啡館里手忙腳亂——它想幫用戶點杯咖啡,但需要先寫代碼調用天氣API(“今天下…

Grafana將棄用AngularJS-我們該如何遷移

AngularJS 棄用時間線 AngularJS 支持已在 Grafana 9 中正式棄用。在 2024 年 5 月發布的 Grafana 11 中,所有 Grafana Cloud 和自托管安裝默認關閉該功能。到 Grafana 12 版本時,將完全移除對 AngularJS 的支持,包括配置參數開關 angular_s…

Qt之opengl定點數據添加更多屬性

將顏色數據加入到定點數據中去 shader中代碼 api中的代碼 #include "sunopengl.h"#include <QTime>sunOpengl::sunOpengl(QWidget *parent) { } unsigned int VBO,VAO; float vertices[]{0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.0f, 0.0f, 1.0f…