如何避免Dash重载器每次保存文件时重新执行数据库连接?
解决Dash重载器重复加载远程数据库的问题
问题背景
我在构建Dash仪表盘,启动时从Redshift远程数据库加载数据要花2分钟左右。开启use_reloader=True后,只要修改项目里任意.py文件(比如布局文件ventas.py、filtros.py),重载器就会重启整个进程,重新连接数据库加载数据。我想要的是修改布局后能实时看到变化,不用每次都重新连数据库。
最小复现示例
main.py
import os import psycopg2 import pandas as pd import dash from dash import html estado = {} def cargar_datos(): print("Connecting to DB...") # 耗时约2分钟 conn = psycopg2.connect(host="...", port=5439, database="...", user="...", password="...") estado["data"] = pd.read_sql("SELECT * FROM my_table", conn) conn.close() cargar_datos() app = dash.Dash(__name__) app.layout = html.Div("hello") if __name__ == "__main__": app.run(debug=True, use_reloader=True)
ventas.py
from dash import html layout = html.Div("Ventas")
实际现象
每次保存ventas.py,终端都会打印Connecting to DB...,哪怕只是改了布局里的文字,也会重新走一遍数据库加载流程。
解决办法
方法1:利用环境变量控制仅首次加载数据
Dash基于Flask,重载器启动时会设置WERKZEUG_RUN_MAIN环境变量——主进程里这个值是false,重载后的子进程是true。我们可以用这个变量判断,只在主进程执行数据库加载,同时动态加载布局确保变更实时生效。
修改后的main.py:
import os import psycopg2 import pandas as pd import dash from dash import html estado = {} def cargar_datos(): print("Connecting to DB...") conn = psycopg2.connect(host="...", port=5439, database="...", user="...", password="...") estado["data"] = pd.read_sql("SELECT * FROM my_table", conn) conn.close() # 只在主进程首次启动时加载数据 if os.environ.get("WERKZEUG_RUN_MAIN") != "true": cargar_datos() app = dash.Dash(__name__) # 动态导入布局文件,修改后能实时更新 def get_layout(): from ventas import layout return layout app.layout = get_layout if __name__ == "__main__": app.run(debug=True, use_reloader=True)
方法2:用Flask缓存缓存数据库查询结果
引入flask_caching把查询结果缓存到本地,这样哪怕进程重启,也能直接读缓存,不用重新连数据库。
先装依赖:
pip install flask-caching
修改后的main.py:
import os import psycopg2 import pandas as pd import dash from dash import html from flask_caching import Cache estado = {} app = dash.Dash(__name__) # 配置文件系统缓存,重启进程也能读取缓存 cache = Cache(app.server, config={ 'CACHE_TYPE': 'FileSystemCache', 'CACHE_DIR': 'cache-directory', 'CACHE_DEFAULT_TIMEOUT': 3600 # 缓存1小时,可按需调整 }) # 用缓存装饰器标记查询函数 @cache.memoize() def cargar_datos(): print("Connecting to DB...") conn = psycopg2.connect(host="...", port=5439, database="...", user="...", password="...") data = pd.read_sql("SELECT * FROM my_table", conn) conn.close() return data # 首次加载后自动缓存 estado["data"] = cargar_datos() # 动态加载布局 def get_layout(): from ventas import layout return layout app.layout = get_layout if __name__ == "__main__": app.run(debug=True, use_reloader=True)
方法3:关闭全局重载,仅监听布局文件
如果不需要监听所有.py文件,直接关掉use_reloader,手动指定要监听的布局文件,Dash会在这些文件变更时更新布局,不会重启整个进程。
修改后的main.py:
import os import psycopg2 import pandas as pd import dash from dash import html estado = {} def cargar_datos(): print("Connecting to DB...") conn = psycopg2.connect(host="...", port=5439, database="...", user="...", password="...") estado["data"] = pd.read_sql("SELECT * FROM my_table", conn) conn.close() cargar_datos() app = dash.Dash(__name__) def get_layout(): from ventas import layout return layout app.layout = get_layout if __name__ == "__main__": # 指定要监听的布局文件 extra_files = [ os.path.join(os.getcwd(), "ventas.py"), os.path.join(os.getcwd(), "filtros.py") ] app.run(debug=True, use_reloader=False, extra_files=extra_files)
内容的提问来源于stack exchange,提问作者Francisco Augusto Varela Aguir
相关产品推荐
相关产品推荐

