有没有办法在使用后台回调时更快地更新plotly/dash?
下面的代码使用了一个后台回调(plotly/dash)来获取一个值。
每隔3秒,update_event(event, shared_value)
会设置一个event
并定义一个value
。与此同时,listening_process(set_progress)
在等待这个event
。
当等待时间比较短(比如几秒钟)时,这个方法似乎运行得很好。但是当等待时间低于1秒(比如500毫秒)时,listening_process(set_progress)
就会漏掉一些值。
有没有办法让后台回调更新得更快呢?看起来服务器的更新有几百毫秒的延迟,这和我设置event
的频率无关。
import time
from uuid import uuid4
import diskcache
import dash_bootstrap_components as dbc
from dash import Dash, html, DiskcacheManager, Input, Output
from multiprocessing import Event, Value, Process
from datetime import datetime
import random
# Background callbacks require a cache manager + a unique identifier
launch_uid = uuid4()
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(
cache, cache_by=[lambda: launch_uid], expire=60,
)
# Creating an event
event = Event()
# Creating a shared value
shared_value = Value('i', 0) # 'i' denotes an integer type
# Updating the event
# This will run in a different process using multiprocessing
def update_event(event, shared_value):
while True:
event.set()
with shared_value.get_lock(): # ensure safe access to shared value
shared_value.value = random.randint(1, 100) # generate a random integer between 1 and 100
print("Updating event...", datetime.now().time(), "Shared value:", shared_value.value)
time.sleep(3)
app = Dash(__name__, background_callback_manager=background_callback_manager)
app.layout = html.Div([
html.Button('Run Process', id='run-button'),
dbc.Row(children=[
dbc.Col(
children=[
# Component sets up the string with % progress
html.P(None, id="progress-component")
]
),
]
),
html.Div(id='output')
])
# Listening for the event and generating a random process
def listening_process(set_progress):
while True:
event.wait()
event.clear()
print("Receiving event...", datetime.now().time())
with shared_value.get_lock(): # ensure safe access to shared value
value = shared_value.value # read the shared value
set_progress(value)
@app.callback(
[
Output('run-button', 'style', {'display': 'none'}),
Output("progress-component", "children"),
],
Input('run-button', 'n_clicks'),
prevent_initial_call=True,
background=True,
running=[
(Output("run-button", "disabled"), True, False)],
progress=[
Output("progress-component", "children"),
],
)
def run_process(set_progress, n_clicks):
if n_clicks is None:
return False, None
elif n_clicks > 0:
p = Process(target=update_event, args=(event,shared_value))
p.start()
listening_process(set_progress)
return True, None
if __name__ == '__main__':
app.run(debug=True, port=8050)
编辑:我找到了一种使用interval
的解决方案。
@app.callback(
[
Output('run-button', 'style', {'display': 'none'}),
Output("progress-component", "children"),
],
Input('run-button', 'n_clicks'),
prevent_initial_call=True,
interval= 100, #### **THIS IS NEW**
background=True,
running=[
(Output("run-button", "disabled"), True, False)],
progress=[
Output("progress-component", "children"),
],
)
但是,这种方法相比于dcc.interval
有什么优势呢?在这两种情况下,都是在轮询。唯一的优势似乎是,消费者在值被生成的确切时刻就能收到更新的值。
0 个回答
暂无回答