8 · Caché, estado y disposición
El modelo de re-ejecución tiene un costo: tu script se re-ejecuta constantemente, así que cualquier cosa lenta corre una y otra vez. `@st.cache_resource` carga el modelo UNA VEZ; `@st.cache_data` cachea cómputos puros; `st.session_state` recuerda valores entre re-ejecuciones; y `st.columns`/`st.sidebar`/`st.tabs` organizan la página.
Como todo el script se re-ejecuta constantemente, el cacheo es ESENCIAL: `@st.cache_resource` carga el modelo UNA VEZ y comparte el mismo objeto entre re-ejecuciones (para conexiones/modelos — no hasheables, de larga vida); `@st.cache_data` memoiza cómputos PUROS por sus entradas (para datos/DataFrames — devuelve una copia fresca). `st.session_state` persiste valores entre re-ejecuciones, y `st.columns`/`st.sidebar`/`st.tabs` organizan la página.
Sin esto:
Sin `@st.cache_resource` el modelo se recarga del disco en cada re-ejecución — cada arrastre de slider cuesta una deserialización completa — haciendo la app lentísima; y sin `session_state` pierdes cualquier valor no derivado directamente de un widget.
El modelo de re-ejecución es maravilloso para la simplicidad pero brutal para el rendimiento: como Streamlit re-ejecuta tu script entero en cada interacción, cualquier cosa lenta en ese script corre de nuevo cada vez. Cargar un modelo del disco, consultar una base de datos, procesar un DataFrame grande — todo se re-ejecuta en cada arrastre de slider a menos que lo detengas. Las herramientas para detenerlo son el cacheo, el estado de sesión, y la disposición (layout).
@st.cache_resource — carga el modelo UNA VEZ. Decora la función que carga tu modelo con @st.cache_resource. La primera corrida la ejecuta (lento: deserializar el .joblib); cada re-ejecución posterior obtiene el mismo objeto del modelo de vuelta al instante desde la caché, saltándose la carga por completo. cache_resource es para recursos globales, de larga vida, a menudo no hasheables que quieres compartir entre re-ejecuciones y usuarios: modelos de ML, conexiones de base de datos, clientes de API. Devuelve el mismo objeto (no una copia) — que es justo lo que quieres para un modelo.
@st.cache_data — cachea cómputos puros. Decora una función que computa datos con @st.cache_data. Streamlit memoiza por las entradas de la función: llámala de nuevo con los mismos argumentos y obtienes el resultado cacheado sin recomputar. Es para datos puros y serializables — cargar un CSV, una agregación costosa, un DataFrame transformado. Crucialmente, devuelve una copia fresca en cada llamada, así que mutar el resultado no puede corromper la caché. (La misma idea que la memoización de functools, afinada para datos.)
La distinción que importa: ¿cuál para el modelo? Usa @st.cache_resource para el objeto del modelo — es un único recurso compartido que cargas una vez y reutilizas, no datos indexados por entradas. Usa @st.cache_data para los datos que el modelo consume o produce (un dataset cargado, un lote de filas puntuadas). Elegir cache_data para el modelo es el error clásico: intenta hashear/copiar el modelo, lo cual es incorrecto para un recurso compartido.
st.session_state — recordar entre re-ejecuciones. Como cada re-ejecución arranca el script de cero, las variables ordinarias se reinician cada vez. st.session_state es un diccionario por usuario que sobrevive a las re-ejecuciones: st.session_state["count"] = st.session_state.get("count", 0) + 1 mantiene un contador, un historial de predicciones, una bandera de "¿ha iniciado sesión el usuario?" — cualquier cosa que deba persistir más allá de una sola corrida pero no esté atada al valor actual de un widget.
Layout — organizar la página. Por defecto las llamadas st.* se apilan verticalmente. Para dar forma a la página:
col1, col2 = st.columns(2)— columnas lado a lado; escribe encol1/col2.st.sidebar— un panel izquierdo plegable, perfecto para entradas/filtros (st.sidebar.slider(...)).st.tabs(["A", "B"])— secciones con pestañas para separar, digamos, "Predecir" de "Acerca de".
La celda de solo-lectura muestra una app con disposición: el modelo cargado vía @st.cache_resource, un cargador de datos cacheado vía @st.cache_data, un contador en session_state, y un layout de sidebar + columnas.
Una app de Streamlit que usa `@st.cache_resource` para cargar el modelo una vez, `@st.cache_data` para cachear un cargador de CSV, `st.session_state` para contar re-ejecuciones, y un layout de sidebar + columnas + pestañas.
Estás cargando tu modelo entrenado en una app de Streamlit. ¿Qué decorador de caché debe envolver la función `load_model()`, y por qué?
- `@st.cache_resource` carga el modelo UNA VEZ y comparte el mismo objeto entre re-ejecuciones — úsalo para modelos, conexiones de BD, y otros recursos de larga vida.
- `@st.cache_data` memoiza cómputos puros por sus entradas y devuelve una copia fresca — úsalo para datasets, DataFrames, y agregaciones costosas (NO el modelo).
- `st.session_state` persiste valores entre re-ejecuciones (que de otro modo se reinician), y `st.columns`/`st.sidebar`/`st.tabs` organizan una página que de otro modo va de arriba a abajo.
Toda app de ML real en Streamlit cachea el modelo con `@st.cache_resource` — sin él, el modelo de re-ejecución hace la app inutilizablemente lenta, recargando el artefacto en cada clic.
Si lo quitas: Omite el cacheo y el modelo se deserializa en cada interacción; omite session_state y pierdes cualquier historial o bandera que el panel necesite entre re-ejecuciones.