连接线程和发送信号时遇到问题
Troubles connecting thread and sending a signal
我下面的代码有效,但在程序结束并重新启动几次后,行
thread.started.connect(worker.work)
不会 运行 并且文件不会发送到 GUI。这是问题的细分:
这是我将两个 hdf5 文件发送到文件夹时终端的通常结果:
running API pyqt5
using configuration at imageanalyser/qimageanalyser/image_analyzer.conf
no Pyro installed. Use dummy event handler.
{'coordinates': True, '_actions': {'home': <PyQt5.QtWidgets.QAction object at 0x7f8681235a60>, 'back': <PyQt5.QtWidgets.QAction object at 0x7f8681235af0>, 'forward': <PyQt5.QtWidgets.QAction object at 0x7f8681235b80>, 'pan': <PyQt5.QtWidgets.QAction object at 0x7f8681235ca0>, 'zoom': <PyQt5.QtWidgets.QAction object at 0x7f8681235dc0>, 'configure_subplots': <PyQt5.QtWidgets.QAction object at 0x7f8681235d30>, 'edit_parameters': <PyQt5.QtWidgets.QAction object at 0x7f8681235ee0>, 'save_figure': <PyQt5.QtWidgets.QAction object at 0x7f868123f040>}, 'locLabel': <PyQt5.QtWidgets.QLabel object at 0x7f8681235f70>, 'canvas': <qimageanalyser.mplwidget.MplCanvas object at 0x7f8688935940>, '_nav_stack': <matplotlib.cbook.Stack object at 0x7f868123d850>, '_lastCursor': <Cursors.POINTER: 1>, '_id_press': 2, '_id_release': 3, '_id_drag': 4, '_pan_info': None, '_zoom_info': None, 'mode': <_Mode.NONE: ''>}
try to connect to event service ...
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 1/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 2/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 3/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 4/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 5/350
finished run test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5 2021_08_10_13_43_29 (3rd copy).hdf5
<HDF5 file "2021_08_10_13_43_29 (3rd copy).hdf5" (mode r+)>
analyze_image
xmean 135.47
xstd 41.31
xmean 148.42
xstd 41.17
mass: 3.81923985318e-26 [kg] size: 0.0002074740400778919 [m] tof: 0.01 [s]
mass: 3.81923985318e-26 [kg] size: 0.000122395198908796 [m] tof: 0.01 [s]
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 1/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 2/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 3/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 4/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 5/350
finished run test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5 2021_08_10_13_43_29 (4th copy).hdf5
<HDF5 file "2021_08_10_13_43_29 (4th copy).hdf5" (mode r+)>
analyze_image
xmean 135.47
xstd 41.31
xmean 148.42
xstd 41.17
mass: 3.81923985318e-26 [kg] size: 0.0002074740400778919 [m] tof: 0.01 [s]
mass: 3.81923985318e-26 [kg] size: 0.000122395198908796 [m] tof: 0.01 [s]
但是一旦我结束程序然后重新启动它,可能是第 3 到第 5 次连接没有通过,这里是结果,不管我尝试将新的 hdf5 文件发送到文件夹:
running API pyqt5
using configuration at imageanalyser/qimageanalyser/image_analyzer.conf
no Pyro installed. Use dummy event handler.
{'coordinates': True, '_actions': {'home': <PyQt5.QtWidgets.QAction object at 0x7f8681235a60>, 'back': <PyQt5.QtWidgets.QAction object at 0x7f8681235af0>, 'forward': <PyQt5.QtWidgets.QAction object at 0x7f8681235b80>, 'pan': <PyQt5.QtWidgets.QAction object at 0x7f8681235ca0>, 'zoom': <PyQt5.QtWidgets.QAction object at 0x7f8681235dc0>, 'configure_subplots': <PyQt5.QtWidgets.QAction object at 0x7f8681235d30>, 'edit_parameters': <PyQt5.QtWidgets.QAction object at 0x7f8681235ee0>, 'save_figure': <PyQt5.QtWidgets.QAction object at 0x7f868123f040>}, 'locLabel': <PyQt5.QtWidgets.QLabel object at 0x7f8681235f70>, 'canvas': <qimageanalyser.mplwidget.MplCanvas object at 0x7f8688935940>, '_nav_stack': <matplotlib.cbook.Stack object at 0x7f868123d850>, '_lastCursor': <Cursors.POINTER: 1>, '_id_press': 2, '_id_release': 3, '_id_drag': 4, '_pan_info': None, '_zoom_info': None, 'mode': <_Mode.NONE: ''>}
try to connect to event service ...
最后是受此影响的程序代码。我正在使用 Pycharm 和 thread.started.connect(worker.work)
,特别是单词 connect
被突出显示并且警告消息是 Cannot find reference 'connect' in 'function | pyqtBoundSignal'
:
thread = QThread(parent=self) # this part is in the DesignerMainWindow() __init__() shown below
print('try to connect to event service ...')
worker = watchdog_search.Worker("/home/test_image_analyzer_files/Test_Data/")
worker.moveToThread(thread)
thread.started.connect(worker.work)
thread.start()
worker.new_file.connect(self.on_finished_run)
def run_app():
try:
# first try to get an existing app
app = QtGui.QApplication.instance()
reuseapp = True
if app is None:
app = QtGui.QApplication(sys.argv)
reuseapp = False
except:
pass
dmw = DesignerMainWindow()
dmw.show()
return dmw, app, reuseapp
if __name__ == "__main__":
dmw, app, reuseapp = run_app()
if "app" in globals() and not reuseapp:
sys.exit(app.exec_())
和 watchdog_search 文件。注意这里 self.new_file.emit(event.src_path, os.path.basename(event.src_path))
中的 emit
被突出显示并且警告是 Cannot find reference 'emit' in 'pyqtSignal | pyqtSignal'
:
import time
import traceback
import os
import h5py
import queue
from typing import Union
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, DirCreatedEvent, FileCreatedEvent
from .tools.qt import QtCore
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import (
QObject,
QThread,
pyqtSignal,
pyqtSlot,
)
class NewFileHandler(FileSystemEventHandler):
def __init__(self, q, *a, **k):
super().__init__(*a, **k)
self._q = q
def on_created(self, event):
self._q.put(event)
class Worker(QObject):
new_file = pyqtSignal(str,str)
def __init__(self, path):
super().__init__()
self._q = queue.Queue()
observer = Observer()
handler = NewFileHandler(self._q)
observer.schedule(handler, path=path, recursive=True)
# starts a background thread! Thus we need to wait for the
# queue to receive the events in work.
observer.start()
def work(self):
while True:
event = self._q.get()
max_retry_count = 350 # for test purposes now but want to set an upper bound on verifying a file is
# finished.
retry_interval_seconds = .01 # every hundreth it will try the file to see if it finished writing
retry_count = 0
if event.event_type == "created" and event.src_path.lower().endswith(".hdf5"):
while True:
try:
file = h5py.File(event.src_path, "r")
file.close()
except OSError:
if retry_count < max_retry_count:
retry_count += 1
print(f"h5 file <{event.src_path}> is locked, retrying {retry_count}/{max_retry_count}")
time.sleep(retry_interval_seconds)
else:
print(f"h5 file <{event.src_path}> reached max retry count, skipping")
break # <--- looks useful here
except Exception as err:
print(f"Got unexpected Error <{type(err).__name__}> while opening <{event.src_path}> ")
traceback.print_exc()
else:
self.new_file.emit(event.src_path, os.path.basename(event.src_path))
break
我使用守护进程线程解决了这个问题:
worker = watchdog_search.Worker("/home/test_image_analyzer_files/Test_Data/")
worker.new_file.connect(self.on_finished_run)
thread = threading.Thread(target=worker.work)
thread.setDaemon(True)
thread.start()
我下面的代码有效,但在程序结束并重新启动几次后,行
thread.started.connect(worker.work)
不会 运行 并且文件不会发送到 GUI。这是问题的细分:
这是我将两个 hdf5 文件发送到文件夹时终端的通常结果:
running API pyqt5
using configuration at imageanalyser/qimageanalyser/image_analyzer.conf
no Pyro installed. Use dummy event handler.
{'coordinates': True, '_actions': {'home': <PyQt5.QtWidgets.QAction object at 0x7f8681235a60>, 'back': <PyQt5.QtWidgets.QAction object at 0x7f8681235af0>, 'forward': <PyQt5.QtWidgets.QAction object at 0x7f8681235b80>, 'pan': <PyQt5.QtWidgets.QAction object at 0x7f8681235ca0>, 'zoom': <PyQt5.QtWidgets.QAction object at 0x7f8681235dc0>, 'configure_subplots': <PyQt5.QtWidgets.QAction object at 0x7f8681235d30>, 'edit_parameters': <PyQt5.QtWidgets.QAction object at 0x7f8681235ee0>, 'save_figure': <PyQt5.QtWidgets.QAction object at 0x7f868123f040>}, 'locLabel': <PyQt5.QtWidgets.QLabel object at 0x7f8681235f70>, 'canvas': <qimageanalyser.mplwidget.MplCanvas object at 0x7f8688935940>, '_nav_stack': <matplotlib.cbook.Stack object at 0x7f868123d850>, '_lastCursor': <Cursors.POINTER: 1>, '_id_press': 2, '_id_release': 3, '_id_drag': 4, '_pan_info': None, '_zoom_info': None, 'mode': <_Mode.NONE: ''>}
try to connect to event service ...
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 1/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 2/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 3/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 4/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5> is locked, retrying 5/350
finished run test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (3rd copy).hdf5 2021_08_10_13_43_29 (3rd copy).hdf5
<HDF5 file "2021_08_10_13_43_29 (3rd copy).hdf5" (mode r+)>
analyze_image
xmean 135.47
xstd 41.31
xmean 148.42
xstd 41.17
mass: 3.81923985318e-26 [kg] size: 0.0002074740400778919 [m] tof: 0.01 [s]
mass: 3.81923985318e-26 [kg] size: 0.000122395198908796 [m] tof: 0.01 [s]
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 1/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 2/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 3/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 4/350
h5 file <test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5> is locked, retrying 5/350
finished run test_image_analyzer_files/Test_Data/2021_08_10_13_43_29 (4th copy).hdf5 2021_08_10_13_43_29 (4th copy).hdf5
<HDF5 file "2021_08_10_13_43_29 (4th copy).hdf5" (mode r+)>
analyze_image
xmean 135.47
xstd 41.31
xmean 148.42
xstd 41.17
mass: 3.81923985318e-26 [kg] size: 0.0002074740400778919 [m] tof: 0.01 [s]
mass: 3.81923985318e-26 [kg] size: 0.000122395198908796 [m] tof: 0.01 [s]
但是一旦我结束程序然后重新启动它,可能是第 3 到第 5 次连接没有通过,这里是结果,不管我尝试将新的 hdf5 文件发送到文件夹:
running API pyqt5
using configuration at imageanalyser/qimageanalyser/image_analyzer.conf
no Pyro installed. Use dummy event handler.
{'coordinates': True, '_actions': {'home': <PyQt5.QtWidgets.QAction object at 0x7f8681235a60>, 'back': <PyQt5.QtWidgets.QAction object at 0x7f8681235af0>, 'forward': <PyQt5.QtWidgets.QAction object at 0x7f8681235b80>, 'pan': <PyQt5.QtWidgets.QAction object at 0x7f8681235ca0>, 'zoom': <PyQt5.QtWidgets.QAction object at 0x7f8681235dc0>, 'configure_subplots': <PyQt5.QtWidgets.QAction object at 0x7f8681235d30>, 'edit_parameters': <PyQt5.QtWidgets.QAction object at 0x7f8681235ee0>, 'save_figure': <PyQt5.QtWidgets.QAction object at 0x7f868123f040>}, 'locLabel': <PyQt5.QtWidgets.QLabel object at 0x7f8681235f70>, 'canvas': <qimageanalyser.mplwidget.MplCanvas object at 0x7f8688935940>, '_nav_stack': <matplotlib.cbook.Stack object at 0x7f868123d850>, '_lastCursor': <Cursors.POINTER: 1>, '_id_press': 2, '_id_release': 3, '_id_drag': 4, '_pan_info': None, '_zoom_info': None, 'mode': <_Mode.NONE: ''>}
try to connect to event service ...
最后是受此影响的程序代码。我正在使用 Pycharm 和 thread.started.connect(worker.work)
,特别是单词 connect
被突出显示并且警告消息是 Cannot find reference 'connect' in 'function | pyqtBoundSignal'
:
thread = QThread(parent=self) # this part is in the DesignerMainWindow() __init__() shown below
print('try to connect to event service ...')
worker = watchdog_search.Worker("/home/test_image_analyzer_files/Test_Data/")
worker.moveToThread(thread)
thread.started.connect(worker.work)
thread.start()
worker.new_file.connect(self.on_finished_run)
def run_app():
try:
# first try to get an existing app
app = QtGui.QApplication.instance()
reuseapp = True
if app is None:
app = QtGui.QApplication(sys.argv)
reuseapp = False
except:
pass
dmw = DesignerMainWindow()
dmw.show()
return dmw, app, reuseapp
if __name__ == "__main__":
dmw, app, reuseapp = run_app()
if "app" in globals() and not reuseapp:
sys.exit(app.exec_())
和 watchdog_search 文件。注意这里 self.new_file.emit(event.src_path, os.path.basename(event.src_path))
中的 emit
被突出显示并且警告是 Cannot find reference 'emit' in 'pyqtSignal | pyqtSignal'
:
import time
import traceback
import os
import h5py
import queue
from typing import Union
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, DirCreatedEvent, FileCreatedEvent
from .tools.qt import QtCore
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import (
QObject,
QThread,
pyqtSignal,
pyqtSlot,
)
class NewFileHandler(FileSystemEventHandler):
def __init__(self, q, *a, **k):
super().__init__(*a, **k)
self._q = q
def on_created(self, event):
self._q.put(event)
class Worker(QObject):
new_file = pyqtSignal(str,str)
def __init__(self, path):
super().__init__()
self._q = queue.Queue()
observer = Observer()
handler = NewFileHandler(self._q)
observer.schedule(handler, path=path, recursive=True)
# starts a background thread! Thus we need to wait for the
# queue to receive the events in work.
observer.start()
def work(self):
while True:
event = self._q.get()
max_retry_count = 350 # for test purposes now but want to set an upper bound on verifying a file is
# finished.
retry_interval_seconds = .01 # every hundreth it will try the file to see if it finished writing
retry_count = 0
if event.event_type == "created" and event.src_path.lower().endswith(".hdf5"):
while True:
try:
file = h5py.File(event.src_path, "r")
file.close()
except OSError:
if retry_count < max_retry_count:
retry_count += 1
print(f"h5 file <{event.src_path}> is locked, retrying {retry_count}/{max_retry_count}")
time.sleep(retry_interval_seconds)
else:
print(f"h5 file <{event.src_path}> reached max retry count, skipping")
break # <--- looks useful here
except Exception as err:
print(f"Got unexpected Error <{type(err).__name__}> while opening <{event.src_path}> ")
traceback.print_exc()
else:
self.new_file.emit(event.src_path, os.path.basename(event.src_path))
break
我使用守护进程线程解决了这个问题:
worker = watchdog_search.Worker("/home/test_image_analyzer_files/Test_Data/")
worker.new_file.connect(self.on_finished_run)
thread = threading.Thread(target=worker.work)
thread.setDaemon(True)
thread.start()