我正在編寫的一些分析代碼之上構建一個界面,該代碼執行一些 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
提交
取消