Based on inputs from @fohrloop and @chriddyp, i have come up with a new syntax (available in dash-extensions 0.0.28). The performance should be the same, but the syntax is simpler (at least that is the intention). Here is the benchmark example using the new syntax,
import datetime
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import pandas as pd
from dash_extensions.enrich import Dash, ServersideOutput, Output, Input, State, Trigger
# Drop down options.
options = [{"label": x, "value": x} for x in [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000]]
# Create app.
app = Dash(prevent_initial_callbacks=True)
server = app.server
app.layout = html.Div([
html.Button("Run benchmark (with cache)", id="btn"), dcc.Dropdown(id="dd", options=options, value=1),
dcc.Store(id="time"), dcc.Loading(dcc.Store(id="store"), fullscreen=True, type="dot"), html.Div(id="log")
])
@app.callback([ServersideOutput("store", "data"), ServersideOutput("time", "data")],
Trigger("btn", "n_clicks"), State("dd", "value"))
def query(value):
df = pd.DataFrame(data=np.random.rand(int(value)), columns=["rnd"])
return df, datetime.datetime.now()
@app.callback(Output("log", "children"), Input("store", "data"), State("time", "data"))
def calc(df, time):
toc = datetime.datetime.now()
mean = df["rnd"].mean()
return "ELAPSED = {}s (and mean is {:.3f})".format((toc - time).total_seconds(), mean)
if __name__ == '__main__':
app.run_server()
So what has changed? Instead of having to register the callbacks on the Dash
app object, you now just have to use the custom objects from dash_extensions.enrich
. The cached_callback
decorator has been abandoned. You now just use the normal callback
decorator and indicate which outputs should stay server side by using ServersideOutput
instead of Output
.