I have recently (last 2 days) started using Dash multiple outputs.The hope is that it would speed things up whilst simultaneously reduce the amount of code needed.
However it seems that it has only reduce the amount of code (which is good). However the number of XHR and fetch requests has increased. It doesn’t look like it runs any more slowly however I am surprised that the number has increased.
It would be really good to have a better idea of how these things work and why it generates more callbacks and not less.
When I run this code I get 2 network requests every time I click “Click Me”:
import dash
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Button('Click Me', id='click-me'),
html.Div(0, id='counter-1'),
html.Div(0, id='counter-2'),
])
@app.callback(output=dash.dependencies.Output('counter-1', 'children'),
inputs=[dash.dependencies.Input('click-me', 'n_clicks')])
def click1(n_clicks):
if n_clicks is None:
raise dash.exceptions.PreventUpdate
return n_clicks
@app.callback(output=dash.dependencies.Output('counter-2', 'children'),
inputs=[dash.dependencies.Input('click-me', 'n_clicks')])
def click2(n_clicks):
if n_clicks is None:
raise dash.exceptions.PreventUpdate
return n_clicks
if __name__ == '__main__':
app.run_server()
But when I run this code I get 1 network request every time I click me:
import dash
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Button('Click Me', id='click-me'),
html.Div(0, id='counter-1'),
html.Div(0, id='counter-2'),
])
@app.callback(output=[dash.dependencies.Output('counter-1', 'children'),
dash.dependencies.Output('counter-2', 'children')],
inputs=[dash.dependencies.Input('click-me', 'n_clicks')])
def all_clicks(n_clicks):
if n_clicks is None:
raise dash.exceptions.PreventUpdate
return n_clicks, n_clicks
if __name__ == '__main__':
app.run_server()
For one of my callback intensive apps I’ve found optimal performance between 10 and 20 outputs, more than that and the client end seems to be slow at updating the separate elements.
The app I am running is huge and has around 100 callbacks written in the code. The app essentially functions as multiple small apps bundled.
I combined about 40 callbacks into 4. This resulted in the number of XHR and fetch requests going from 144 to 170.
What it looked like was happening was that when a callback was combined it sometimes changed the order in which the callbacks ran. So previously rather than callback a running and then callback b running it ended up as callback b runs then a which causes b.
Is it possible that using the multiple callback could result in a change in the order than callbacks get run?
If callbacks are triggering other callbacks then yes you are ultimately generating a different graph of callbacks which will result in a different sequence of how they are called. Have you tried using the new dev tools to investigate?
FYI I have a page that originally had 300 callbacks on it and I reduced it to around 25, the page performance is remarkably better but I did very specifically thinking about how callbacks were triggering each other.