此演示应用程序使用 Plotly / Dash 用户界面运行 python 进程。当使用
app.run_server(debug=True)
启动 Dash 时,会出现以下错误:
Exception in thread Thread-1 (dashfun):
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
. . . some more source files threading --> dash --> flask --> werkzeug . . .
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/signal.py", line 56, in signal
handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread of the main interpreter
程序启动两个线程,一个运行 Dash,另一个执行实际工作。两个队列,一个用于将命令传输到进程,一个用于响应 Dash 查询。
关于如何解决此问题和/或如何将 Dash 用户界面添加到后台运行的程序的建议值得赞赏。
这是程序:
''' Dash in Thread
'''
import time
import queue
import threading
from dash import Dash, html, dcc, callback, Output, Input, State
from dash.exceptions import PreventUpdate
# Make queues
comqueue = queue.Queue() # commands from dash to process
respqueue = queue.Queue() # response from process to dash
# Dash Function
def dashfun(comqueue, respqueue):
app = Dash('ThreadTest')
app.layout = html.Div([
html.H1('Dash Thread Test'),
dcc.Interval(id='valsinter', interval = 2000, n_intervals=0),
html.Slot(id='valsout'),
html.Div(['Set Delta: ',
dcc.Input(id='deltain', type='number', value = 0.0, debounce=True),
html.Slot(id='dump')])
])
@callback(
Output('valsout','children'),
Input('valsinter','n_intervals'),
State('valsout','children')
)
def update_value(n,value):
print('Update_Value ' + repr(value))
try:
# WARNING: This won't work if more than one dash is open
resp = respqueue.get(timeout = 0.01)
print('dash - got resp = '+resp)
except queue.Empty:
resp = None
if resp:
value = 'Value = %.2f' % float(resp.strip())
return value
@callback(
Output('dump','children'),
Input('deltain','value')
)
def new_delta(delta):
print('New Delta: ' + repr(delta))
comqueue.put('%.2f' % delta)
raise PreventUpdate
return repr(delta)
app.run_server(debug=True) # Debug doesn't seem to be working :-\
# Process function
def profun(comqueue, respqueue):
value = 0.0
delta = 0.1
while True:
# Check for new delta in command queue
try:
resp = comqueue.get(timeout = 0.01)
print('process - got command = '+resp)
except queue.Empty:
resp = None
if resp:
delta = float(resp.strip())
# Update value, print and send to response queue
value += delta
print('Val = %.1f' % value )
respqueue.put('%.2f' % value)
time.sleep(4.0)
# Start threads
dthread = threading.Thread(target = dashfun, args = (comqueue, respqueue))
pthread = threading.Thread(target = profun, args = (comqueue, respqueue))
dthread.start()
pthread.start()
该程序在
app.run_server(debug=False)
下大部分运行良好。但是当客户端连接时它仍然会引发错误:
Error importing optional module IPython.core.display
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/_plotly_utils/optional_imports.py", line 30, in get_module
return import_module(name)
. . . importlib --> IPython --> futures . . .
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1504, in _register_atexit
raise RuntimeError("can't register atexit after shutdown")
RuntimeError: can't register atexit after shutdown
目标是在 Dash
debug=True
模式下无错误运行,并且 Dash 在线程中运行。
在主线程中运行
dashfun(comqueue,respqueue)
时(而不是为 Dash 使用第二个线程),它似乎无需 debug=True
即可工作。主线程中的 debug=True
和 dashfun()
似乎有两个 pthreads 同时运行。
Sanskar Biswal回答了问题plotly/dash-core-components/issues/952#issuecomment-2015163046:
引用他的话:
尝试使用以下方法
app.run_server(debug=True, use_reloader=False)