「哎呀!資料表又要重新載入了…」
黑蛋發現目前在系外行星資料表篩選器app中每操作一次篩選,都會再次呼叫get_exoplanet_table_by_astroquery()函式,以致於要再次等待資料表載入。他了解到這是因為Streamlit app是基於一個Python script執行結果所呈現的頁面,每在頁面中做一次操作,會更新Python script中的變數,進而重新執行整個Python script以更新頁面。黑蛋心想,每次都要等待同樣的資料重新載入,這會是一個蠻差的使用者體驗,他得研究看看是否能解決這個問題。
起初,黑蛋找到@st.cache這個decorator可以加在get_exoplanet_table_by_astroquery()函式上方,它會將函式回傳值(value),以及由函式名稱、函式內的程式碼、傳進函式中的參數等資訊所組合成的雜湊值(key),以key-value綁定儲存到快取記憶體中,當函式再次被呼叫時,會先檢查上述資訊的組合是否有變化,若無變化,則略過函式執行步驟,直接從記憶體中取得之前暫存的函式回傳值,以縮減等待時間。
不過,黑蛋進一步發現,Streamlit的開發團隊將會棄用@st.cache,如文件中的說明,因為@st.cache涵蓋不同的使用情境,導致它的程式較為複雜且會拖慢執行速度,所以目前將之拆分成兩個實驗性質的decorator:@st.experimental_memo和@st.experimental_singleton,前者用來暫存經由函式計算、下載的資料,後者則是暫存非資料類的物件,例如session、資料庫連線等資訊,未來兩者都會成為正式的功能以取代@st.cache。
黑蛋選擇用@st.experimental_memo來快取get_exoplanet_table_by_astroquery()函式所回傳的資料表,並設定暫存效期為一天。此外,他還用了st.experimental_memo.clear(),讓使用者能為了取得最新的資料表而手動清除快取。如此一來,原本資料表會一直重新載入的問題就解決啦。
# exoplanet_table_filter.py
import streamlit as st
from astroquery.ipac.nexsci.nasa_exoplanet_archive import NasaExoplanetArchive
@st.experimental_memo(ttl=86400, show_spinner=False)
def get_exoplanet_table_by_astroquery():
table_name = 'pscomppars'
columns = 'pl_name,hostname,sy_dist,pl_orbper,pl_bmasse,pl_rade,disc_year,discoverymethod'
exoplanet_table = NasaExoplanetArchive.query_criteria(
table=table_name, select=columns
)
exoplanet_table = exoplanet_table.to_pandas()
exoplanet_table = exoplanet_table.rename(
columns={
'pl_name': '行星名稱',
'hostname': '所屬恆星名稱',
'sy_dist': '與地球的距離(單位:秒差距)',
'pl_orbper': '行星軌道週期(單位:天)',
'pl_bmasse': '行星質量(單位:地球質量)',
'pl_rade': '行星半徑(單位:地球半徑)',
'disc_year': '發現年份',
'discoverymethod': '發現方法'
}
)
exoplanet_table.sort_values(
by='發現年份', ascending=False, inplace=True, ignore_index=True
)
return exoplanet_table
# 中略
if st.sidebar.button('清除資料表快取'):
st.experimental_memo.clear()
st.balloons()
st.sidebar.success('已清除快取,請重新載入頁面')
此系列文由蘇羿豪撰寫,以「創用CC 姓名標示 4.0(CC BY 4.0)國際版授權條款」釋出。此系列文也同步在Matters及Mirror平台連載。