在一個視窗中,我有一個按鈕,單擊該按鈕后,我想從另一個模塊執行一個方法。此方法需要不確定的時間來執行,并且取決于終端中的用戶輸入。此方法創建一個檔案并重復打開它,將內容寫入檔案,然后關閉檔案。在運行的同時,我在視窗中有一個 matplotlib 圖形小部件,其中包含一個繪圖,每次通過讀取和繪制檔案最新行中的資料將新內容寫入檔案時,我都想更新該繪圖。
為了檢查檔案的更改,我使用了 QFileSystemWatcher。現在,當 userInputFunction() 運行時什么也沒有發生,但是當它完成時我得到“data/runName_Rec.txt dataFileCreated”。如果我然后以任何方式手動編輯檔案,繪圖就會發生。因此,觀察者似乎只是再次開始作業,并在 userInputFunction() 完成后看到目錄發生了變化。
如何正確執行多執行緒處理,以便在 userInputFunction() 運行時觀察器作業?
據我了解,如果我在 QT 程式的主執行緒中運行它,則在用戶輸入函式完成之前,我的應用程式中的任何內容都不會回應。為了解決這個問題,我嘗試按照以下示例將用戶輸入法的執行移動到作業執行緒中:https : //realpython.com/python-pyqt-qthread/。在這個工人中,我有兩種方法。一個簡單地使用 sleep() 執行 for 回圈,這需要一段時間,與示例完全相同。另一個運行我的 userInputFunction()。for 回圈方法 run() 不會凍結 GUI。但是,執行我想要的實際程序的 runScan() 仍然凍結 GUI。我不確定這里發生了什么。我不確定這是否意味著我沒有正確地進行執行緒處理,或者是否正在發生其他事情。
這是我的代碼相關部分的簡化示例。
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from pyqtgraph import PlotWidget
from PyQt5.QtCore import QObject, QThread, pyqtSignal
import pyqtgraph as pg
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog, QMainWindow
import os
from os.path import exists
import csv
import numpy as np
import pandas as pd
import myModule
dirname = os.path.dirname(__file__)
# Create a worker class
class Worker(QObject):
finished = pyqtSignal()
#This works without freezing the GUI
def run(self):
"""Long-running task."""
for i in range(5):
time.sleep(1)
print("step ",i," done!")
self.finished.emit()
#This freezes the GUI
def runScan(self,param1,param2):
"""Long-running task with user input from terminal."""
myModule.userInputFunction(param1,param2)
self.finished.emit()
class someWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(someWindow, self).__init__(*args, **kwargs)
#Load the UI Page
uic.loadUi('somewindow.ui', self)
self.directoryPath = "data"
self.fs_watcher = QtCore.QFileSystemWatcher()
self.fs_watcher.addPath(self.directoryPath)
self.fs_watcher.directoryChanged.connect(self.dataFileCreated)
self.StartScanButton.clicked.connect(self.runLongTask)
self.EndScanButton.clicked.connect(self.endScan)
def dataFileCreated(self):
self.filePath = os.path.join(dirname, "data/" self.runNameBox.toPlainText() "_Rec.txt")
print(self.filePath "dataFileCreated")
self.fs_watcher.addPath(self.filePath)
self.fs_watcher.fileChanged.connect(self.update_graph)
def update_graph(self):
if exists(self.path):
print("file exists!")
#then read the filePath.txt and plots the data
else:
print("file doesn't exist yet")
def endScan(self):
#change some display things
def runLongTask(self):
# Create a QThread object
self.thread = QThread()
# Create a worker object
self.worker = Worker()
# Move worker to the thread
self.worker.moveToThread(self.thread)
# Connect signals and slots
#This results in the GUI freezing
self.thread.started.connect(self.worker.runScan(self.param1,self.param2))
#This DOES NOT result in the GUI freezing
#self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
# Start the thread
self.thread.start()
# Final resets
self.thread.finished.connect(
lambda: print("long task done!")
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = someWindow()
w.show()
sys.exit(app.exec_())
uj5u.com熱心網友回復:
由于此行,GUI 在您的情況下凍結:
self.thread.started.connect(self.worker.runScan(self.param1,self.param2))
這會導致runScan從主執行緒執行并阻塞任何內容直到完成,包括connect.
這也是一個嚴重的錯誤,因為connect總是期望一個可呼叫的作為引數,一旦runScan最終完成它的作業,它就會回傳None并且你的程式將崩潰。
假設在創建執行緒時添加了引數,您可以將這些引數添加到Worker建構式中,然后在 中執行所需的代碼run:
class Worker(QObject):
finished = pyqtSignal()
def __init__(self, param1, param2):
super().__init__()
self.param1 = param1
self.param2 = param2
def run(self):
myModule.userInputFunction(self.param1, self.param2)
self.finished.emit()
class someWindow(QtWidgets.QMainWindow):
# ...
def runLongTask(self):
self.thread = QThread()
self.worker = Worker(self.param1, self.param2)
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
請注意,它不像 QFileSystemWatcher 在處理時“停止”:問題在于,通過runScan在主執行緒中運行,您完全阻塞了主執行緒(不僅是 UI),從而阻止觀察者處理作業系統發送給它通知的事件關于變化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/325560.html
上一篇:如何在多核處理器中調度任務
下一篇:前端之變(七):前端的困境
