我正在编写的一些分析代码之上构建一个界面,该代码执行一些 SQL 并处理查询结果。在我想向用户公开的这个分析代码中,有许多事件的日志记录。因为分析代码运行时间相当长,而且我不希望 UI 被阻塞,所以到目前为止我是通过将分析函数放入自己的线程来完成的。我现在拥有的简化示例(完整脚本):import sysimport timeimport loggingfrom PySide2 import QtCore, QtWidgetsdef long_task(): logging.info('Starting long task') time.sleep(3) # this would be replaced with a real task logging.info('Long task complete')class LogEmitter(QtCore.QObject): sigLog = QtCore.Signal(str)class LogHandler(logging.Handler): def __init__(self): super().__init__() self.emitter = LogEmitter() def emit(self, record): msg = self.format(record) self.emitter.sigLog.emit(msg)class LogDialog(QtWidgets.QDialog): def __init__(self, parent=None): super().__init__(parent) log_txt = QtWidgets.QPlainTextEdit(self) log_txt.setReadOnly(True) layout = QtWidgets.QHBoxLayout(self) layout.addWidget(log_txt) self.setWindowTitle('Event Log') handler = LogHandler() handler.emitter.sigLog.connect(log_txt.appendPlainText) logger = logging.getLogger() logger.addHandler(handler) logger.setLevel(logging.INFO)class Worker(QtCore.QThread): results = QtCore.Signal(object) def __init__(self, func, *args, **kwargs): super().__init__() self.func = func self.args = args self.kwargs = kwargs def run(self): results = self.func(*self.args, **self.kwargs) self.results.emit(results)class MainWindow(QtWidgets.QMainWindow):这工作正常,除了我需要能够允许用户停止执行分析代码。我读过的一切都表明没有办法很好地中断线程,所以使用multiprocessing库似乎是要走的路(没有办法重新编写分析代码以允许定期轮询,因为大部分时间是只花等待查询返回结果)。通过使用multiprocessing.Pool和以不阻塞 UI 的方式执行分析代码,很容易获得相同的功能apply_async。但我似乎无法弄清楚如何从子进程检索日志输出并将其传递给父进程以更新日志对话框。我已经阅读了几乎所有关于此的 SO 问题以及如何处理从多个进程写入单个日志文件的食谱示例,但我无法围绕如何使这些想法适应我的想法我想在这里做。
2 回答

繁星淼淼
TA贡献1775条经验 获得超11个赞
信号不会在进程之间传输数据,因此对于这种情况,必须使用管道然后发出信号:
# other imports
import threading
# ...
class LogHandler(logging.Handler):
def __init__(self):
super().__init__()
self.r, self.w = multiprocessing.Pipe()
self.emitter = LogEmitter()
threading.Thread(target=self.listen, daemon=True).start()
def emit(self, record):
msg = self.format(record)
self.w.send(msg)
def listen(self):
while True:
try:
msg = self.r.recv()
self.emitter.sigLog.emit(msg)
except EOFError:
break
# ...
添加回答
举报
0/150
提交
取消