亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于Streamlit性能優(yōu)化:緩存與狀態(tài)管理實(shí)戰(zhàn)

 更新時(shí)間:2025年04月23日 09:50:20   作者:echola_mendes  
這篇文章主要介紹了關(guān)于Streamlit性能優(yōu)化:緩存與狀態(tài)管理實(shí)戰(zhàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Streamlit性能優(yōu)化:緩存與狀態(tài)管理

Streamlit 是一個(gè)開源的 Python 庫,專為快速構(gòu)建數(shù)據(jù)科學(xué)和機(jī)器學(xué)習(xí) Web 應(yīng)用而設(shè)計(jì)。它無需前端開發(fā)經(jīng)驗(yàn),通過簡單 API 即可創(chuàng)建交互式界面,適合原型開發(fā)和數(shù)據(jù)展示

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

核心特性

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

安裝Streamlit

pip3 install streamlit

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

import streamlit as st

# 顯示標(biāo)題
st.title("Hello World,I'm echola")

# 顯示文本
st.write("這是一個(gè)由Streamlit搭建的Web平臺(tái)")

運(yùn)行:

 streamlit run hello.py

結(jié)果:

是不是很強(qiáng)悍,三行代碼搞定一個(gè)Web應(yīng)用

運(yùn)行原理

Streamlit 的運(yùn)行邏輯圍繞腳本的線性執(zhí)行響應(yīng)式更新展開,其核心設(shè)計(jì)是讓開發(fā)者以極簡的方式構(gòu)建交互式應(yīng)用。以下是關(guān)鍵邏輯分步解析:

1、啟動(dòng)Web服務(wù)器

  • Streamlit 啟動(dòng)一個(gè)本地 Web 服務(wù)器,默認(rèn)監(jiān)聽 8501 端口
  • 打開瀏覽器并導(dǎo)航到 http://localhost:8501,展示應(yīng)用界面

2、解析和執(zhí)行腳本:

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

3、組件渲染

  • 每個(gè) Streamlit 組件(如 st.title 和 st.write)會(huì)被注冊(cè)到當(dāng)前頁面的狀態(tài)中
  • 頁面會(huì)根據(jù)組件的順序和內(nèi)容進(jìn)行渲染

4、實(shí)時(shí)更新:

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

上述增量更新可能會(huì)有一點(diǎn)矛盾,簡而言之就是,「全腳本執(zhí)行 + 差異更新」的設(shè)計(jì),讓 Streamlit 在開發(fā)便捷性(無需手動(dòng)管理更新)和運(yùn)行效率(局部渲染)之間取得了完美平衡

(1)全腳本執(zhí)行

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

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

import time
import streamlit as st

# 全腳本執(zhí)行部分:以下代碼每次交互都會(huì)運(yùn)行
st.title("TimeOut Example")  # ? 標(biāo)題會(huì)重復(fù)渲染,但 Streamlit 會(huì)優(yōu)化為"增量更新"

# 局部增量執(zhí)行:以下代碼僅在按鈕點(diǎn)擊時(shí)觸發(fā)
if st.button("Click me"):
    processing_bar = st.progress(0)  # 每次點(diǎn)擊時(shí)新建進(jìn)度條
    with st.spinner("Loading..."):
        for percent_complete in range(100):
            time.sleep(0.05)
            processing_bar.progress(percent_complete + 1)
    st.success("Loading completed!")

當(dāng)用戶點(diǎn)擊按鈕時(shí),觸發(fā) if 條件判斷,顯示加載提示框 "Loading..."。開始模擬耗時(shí)操作,通過循環(huán)和 time.sleep 模擬耗時(shí)。每次循環(huán)中,更新進(jìn)度條的值,進(jìn)度條從0%逐漸增加到100%

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

再次點(diǎn)擊【Click me】, 重復(fù)上述效果圖

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

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

接下來會(huì)使用緩存機(jī)制進(jìn)行優(yōu)化

(2)差異更新

可以高效渲染(減少網(wǎng)絡(luò)傳輸數(shù)據(jù)量和瀏覽器渲染開銷)和無縫體驗(yàn)(用戶輸入狀態(tài),如:文本框焦點(diǎn)、滾動(dòng)條位置,不會(huì)因?yàn)榫植扛露鴣G失)

??:也要關(guān)注復(fù)雜UI的組件鍵(Key)的穩(wěn)定性

緩存機(jī)制

為什么使用緩存?

問題:每次點(diǎn)擊click按鈕時(shí),代碼會(huì)從執(zhí)行整個(gè)耗時(shí)操作(for循環(huán)+time.sleep),即使操作結(jié)果不變

緩存的作用:將耗時(shí)操作的結(jié)果緩存起來,后續(xù)重復(fù)調(diào)用時(shí)直接讀取緩存,避免重復(fù)計(jì)算

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

@st.cache_data
def heavy_computation():
    # 此函數(shù)僅在輸入?yún)?shù)或代碼變更時(shí)重新執(zhí)行
    return result

使用@st.cache_data的優(yōu)化方案

那優(yōu)化一下上面提到的問題

import time
import streamlit as st

st.title("Optimize Example")

# 緩存耗時(shí)操作的結(jié)束(假設(shè)操作是無參數(shù))
@st.cache_data
def expensive_operation():
    # 模擬耗時(shí)操作(例如:數(shù)據(jù)計(jì)算)
    result = []
    for _ in range(100):
        time.sleep(0.05)  # 假設(shè)這是實(shí)際的計(jì)算步驟
        result.append(_)  # 模擬中間結(jié)果
    return result

if st.button("Click me"):
    processing_bar = st.progress(0)  # 每次點(diǎn)擊時(shí)新建進(jìn)度條
    with st.spinner("Loading..."):
        # 獲取數(shù)據(jù)(首次點(diǎn)擊執(zhí)行耗時(shí)操作,后續(xù)點(diǎn)擊直接讀緩存)
        data = expensive_operation()
        for percent_complete in range(len(data)):
            processing_bar.progress(percent_complete + 1)
    st.success("Loading completed!")

首次點(diǎn)擊【Click me】,會(huì)出現(xiàn)

大概5s后,執(zhí)行完成

重復(fù)點(diǎn)擊【Click me】 ,不會(huì)重復(fù)加載進(jìn)度條,由于直接讀取緩存結(jié)果,無需重復(fù)計(jì)算,數(shù)據(jù)已緩存,進(jìn)度條會(huì)快速更新到100%

通過 @st.cache_data 裝飾器緩存耗時(shí)操作的結(jié)果,避免每次點(diǎn)擊按鈕時(shí)都重新執(zhí)行耗時(shí)操作

不是所有耗時(shí)操作都必須使用緩存

緩存適用場景

需要緩存的場景

  • 耗時(shí)操作的結(jié)果是 靜態(tài)的(例如讀取文件、初始化模型、復(fù)雜計(jì)算)。
  • 操作結(jié)果 不依賴外部變量或用戶輸入。

不適用緩存場景

  • 操作結(jié)果 依賴動(dòng)態(tài)參數(shù)(例如用戶輸入的變量),此時(shí)需通過函數(shù)參數(shù)觸發(fā)緩存更新。
  • 操作需要 實(shí)時(shí)更新(例如每次點(diǎn)擊都需重新計(jì)算)

如果耗時(shí)操作 依賴參數(shù),可以通過函數(shù)參數(shù)控制緩存版本:

@st.cache_data
def expensive_operation(param1, param2):
    # 根據(jù)參數(shù)執(zhí)行不同計(jì)算
    results = []
    for _ in range(100):
        time.sleep(0.05)
        results.append(param1 + param2 + _)
    return results

# 在按鈕點(diǎn)擊時(shí)傳入?yún)?shù)
data = expensive_operation(10, 20)  # 參數(shù)不同會(huì)生成不同緩存

可以看出:

  • 緩存機(jī)制:通過 @st.cache_data 緩存靜態(tài)計(jì)算結(jié)果,減少重復(fù)執(zhí)行。
  • 進(jìn)度條優(yōu)化:將耗時(shí)操作與進(jìn)度條更新分離,首次加載緩存后,后續(xù)交互可快速完成

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

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

  1. 進(jìn)度條重復(fù)創(chuàng)建:每次點(diǎn)擊按鈕都會(huì)新建processing_bar,導(dǎo)致多次點(diǎn)擊時(shí)進(jìn)度條堆疊
  2. 無法阻止重復(fù)提交:在耗時(shí)操作執(zhí)行期間,用戶仍可多次點(diǎn)擊按鈕,導(dǎo)致邏輯混亂
  3. 狀態(tài)丟失:進(jìn)度完成后的狀態(tài)(如success提示)無法持久化

使用st.session_state的優(yōu)化方案

1、保存進(jìn)度條實(shí)例

if "processing_bar" not in st.session_state:
    st.session_state.processing_bar = None  # 初始化進(jìn)度條容器

if st.button("Click me"):
    # 僅在第一次點(diǎn)擊時(shí)創(chuàng)建進(jìn)度條
    if not st.session_state.processing_bar:
        st.session_state.processing_bar = st.progress(0)
    
    # 后續(xù)操作復(fù)用已有進(jìn)度條
    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 = None
    st.success("Done!")

2. 防止重復(fù)提交

if "is_processing" not in st.session_state:
    st.session_state.is_processing = False  # 狀態(tài)鎖

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

3. 持久化完成狀態(tài)

if "load_complete" not in st.session_state:
    st.session_state.load_complete = False

if st.button("Click me"):
    # 執(zhí)行操作...
    st.session_state.load_complete = True

if st.session_state.load_complete:
    st.success("數(shù)據(jù)已加載完成!")
    st.balloons()  # 顯示動(dòng)畫效果

完整優(yōu)化代碼

import time
import streamlit as st

st.title("Optimized Example")

# 初始化會(huì)話狀態(tài)
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 result

if st.button("Click me") and not st.session_state.is_processing:
    st.session_state.is_processing = True
    try:
        # 創(chuàng)建或復(fù)用進(jìn)度條
        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 = True
    finally:
        st.session_state.is_processing = False
        st.session_state.processing_bar = None  # 重置進(jìn)度條

if st.session_state.load_complete:
    st.success("操作成功!")
    st.balloons()

關(guān)鍵作用總結(jié)

會(huì)話狀態(tài)項(xiàng)功能說明
processing_bar保持進(jìn)度條對(duì)象引用,防止重復(fù)創(chuàng)建
is_processing實(shí)現(xiàn)類似互斥鎖,防止重復(fù)提交
load_complete持久化完成狀態(tài),實(shí)現(xiàn)跨腳本執(zhí)行記憶

通過 st.session_state 實(shí)現(xiàn)了:

  1. 狀態(tài)持久化:在 Streamlit 的全腳本重執(zhí)行機(jī)制中保持關(guān)鍵狀態(tài)
  2. 資源管理:避免 DOM 元素重復(fù)創(chuàng)建
  3. 交互安全:防止用戶誤操作導(dǎo)致的邏輯沖突

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

總結(jié)

通過 緩存機(jī)制 減少重復(fù)計(jì)算,結(jié)合 st.session_state 管理會(huì)話狀態(tài),Streamlit 可以高效處理復(fù)雜交互場景,同時(shí)保持代碼簡潔和用戶體驗(yàn)流暢。

這種優(yōu)化策略尤其適合需要頻繁交互、狀態(tài)保持或耗時(shí)操作的 Web 應(yīng)用開發(fā)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python OpenCV基于霍夫圈變換算法檢測圖像中的圓形

    Python OpenCV基于霍夫圈變換算法檢測圖像中的圓形

    這篇文章主要介紹了通過霍夫圈變換算法檢測圖像中的圓形,文中用到的函數(shù)為cv2.HoughCircles(),該函數(shù)可以很好地檢測圓心。感興趣的小伙伴可以了解一下
    2021-12-12
  • 在服務(wù)器端實(shí)現(xiàn)無間斷部署Python應(yīng)用的教程

    在服務(wù)器端實(shí)現(xiàn)無間斷部署Python應(yīng)用的教程

    這篇文章主要介紹了在服務(wù)器端實(shí)現(xiàn)無間斷部署Python應(yīng)用的教程,方法主要是Gunicorn進(jìn)行重載,需要的朋友可以參考下
    2015-04-04
  • Python scrapy爬取蘇州二手房交易數(shù)據(jù)

    Python scrapy爬取蘇州二手房交易數(shù)據(jù)

    scrapy的第二個(gè)實(shí)例對(duì)比上一個(gè),在數(shù)據(jù)處理上增加了新的需求,運(yùn)用了管道文件pipelines.py,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Python中裝飾器兼容加括號(hào)和不加括號(hào)的寫法詳解

    Python中裝飾器兼容加括號(hào)和不加括號(hào)的寫法詳解

    這篇文章主要給大家介紹了關(guān)于Python中裝飾器兼容加括號(hào)和不加括號(hào)寫法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-07-07
  • scikit-learn線性回歸,多元回歸,多項(xiàng)式回歸的實(shí)現(xiàn)

    scikit-learn線性回歸,多元回歸,多項(xiàng)式回歸的實(shí)現(xiàn)

    這篇文章主要介紹了scikit-learn線性回歸,多元回歸,多項(xiàng)式回歸的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 對(duì)python中數(shù)據(jù)集劃分函數(shù)StratifiedShuffleSplit的使用詳解

    對(duì)python中數(shù)據(jù)集劃分函數(shù)StratifiedShuffleSplit的使用詳解

    今天小編就為大家分享一篇對(duì)python中數(shù)據(jù)集劃分函數(shù)StratifiedShuffleSplit的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • wxPython修改文本框顏色過程解析

    wxPython修改文本框顏色過程解析

    這篇文章主要介紹了wxPython修改文本框顏色過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • python使用Geany編輯器配置方法

    python使用Geany編輯器配置方法

    這篇文章主要介紹了python使用Geany編輯器配置方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Python內(nèi)置方法和屬性應(yīng)用:反射和單例(推薦)

    Python內(nèi)置方法和屬性應(yīng)用:反射和單例(推薦)

    這篇文章主要介紹了Python內(nèi)置方法和屬性應(yīng)用:反射和單例,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 詳解 Python 讀寫XML文件的實(shí)例

    詳解 Python 讀寫XML文件的實(shí)例

    這篇文章主要介紹了詳解 Python 讀寫XML文件的實(shí)例的相關(guān)資料,Python 生成XML文件和Python 讀取XML 的實(shí)例,需要的朋友可以參考下
    2017-08-08

最新評(píng)論