亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用多處理,從 PyQt5 應用程序停止子進程,其中子進程不使用事件循環

使用多處理,從 PyQt5 應用程序停止子進程,其中子進程不使用事件循環

猛跑小豬 2023-08-22 10:24:49
我正在構建一個運行神經網絡的 GUI 應用程序。啟動它們效果很好,但我需要能夠在網絡已經運行和工作的情況下中止計算。我構建了一個小型原型,它向您展示了我的應用程序中問題的主要機制。建筑學窗口類別:包含所有 GUI 元素,是啟動和控制一切的主要對象。它包含 aQThreadPool self.__pool和QRunnableObject self.__runner。該QRunnable對象包含神經網絡所需的一切。我使用 QRunnable 對象的原因是,在另一個線程中處理神經網絡時不阻塞 GUI。我還需要在神經網絡和我的應用程序之間進行通信。運行程序類:運行程序類處理主窗口和神經網絡本身之間的通信。神經網絡是一個Process來自多處理的對象,放入self.__net. 為了進行通信,我使用Queue self.__queue. 當 QRunnable 對象啟動時,進程以 開始self.__net.start()。我用無限循環觀察隊列。循環在某些信號上終止。在此示例中,我僅使用 Signal NetSignal.finished。當網絡完成后,我向 Window 對象發送一個信號。RunnerSignal類:由于QRunnables無法使用信號,因此需要該類將一些信號封裝到QRuannaable對象中。Mnist 類:Mnist 類是子進程本身,繼承自Process. 在這個例子中,它運行了一個非常簡單的例子,在神經網絡中處理 mnist 數據集。進程周圍沒有循環,通??捎糜谕V勾祟愖舆M程。當神經網絡完成時,隊列向 QRunnable 對象發送一個信號,以通知進程已完成計算,從而向主窗口發送一個信號。問題我需要能夠以某種方式停止這個過程。我想嘗試用 來殺死它os.kill,但這在我的應用程序中效果不佳。我也嘗試過self.__net.terminate(),self.__net.kill(). 我正在考慮以某種方式將一個對象傳遞到神經網絡的回調參數中,以便中止那里的處理,但我不太確定這是否是正確的方法。
查看完整描述

1 回答

?
白衣非少年

TA貢獻1155條經驗 獲得超0個贊

好吧,現在我已經知道問題出在哪里了。當我終止進程時self.__net.terminate()仍然存在僵尸進程,為什么我認為這不是正確的解決方案。


僵尸進程是由 QRunnable 引起的,它不會終止,因為它正在等待子進程在隊列中發送信號。


因此,我需要一個自定義的“終止”函數,它調用 Terminate() 并向 QRunnable 發送一個信號,表明該過程已完成。這樣,所有進程和線程都會相應終止,并且不會留下任何僵尸進程。


import tensorflow as tf

from sys             import exit, argv

from multiprocessing import Process, Queue

from PyQt5.QtWidgets import QPushButton, QApplication, QHBoxLayout, QWidget, QLabel

from PyQt5.QtCore    import QRunnable, QObject, pyqtSignal, QThreadPool



class Window(QWidget):


    def __init__(self):

        QWidget.__init__(self)


        self.__btn_run = QPushButton("Start")

        self.__btn_stp = QPushButton("Stop")

        self.__label   = QLabel("Idle")


        self.__runner  = Runner()

        self.__pool    = QThreadPool.globalInstance()


        self.__btn_run.clicked.connect(self.__run_net)

        self.__btn_stp.clicked.connect(self.__stp_net)

        self.__runner.signals.finished.connect(self.__on_finished)


        self.__btn_stp.setDisabled(True)


        self.setLayout(QHBoxLayout())

        self.layout().addWidget(self.__btn_run)

        self.layout().addWidget(self.__btn_stp)

        self.layout().addWidget(self.__label)


    def __run_net(self):

        self.__btn_run.setDisabled(True)

        self.__btn_stp.setEnabled(True)

        self.__label.setText("Running")

        self.__pool.start(self.__runner)


    def __stp_net(self):

        self.__runner.close()

        # What to do here?


    def __on_finished(self):

        self.__btn_run.setEnabled(True)

        self.__btn_stp.setDisabled(True)

        self.__label.setText("Finished")

        self.__runner = Runner()



class Runner(QRunnable):


    def __init__(self):

        QRunnable.__init__(self)

        self.__queue = Queue()

        self.__net   = Mnist(self.__queue)

        self.signals = RunnerSignal()


    def run(self):

        self.__net.start()

        while True:

            data = self.__queue.get()

            if data == NetSignal.finished:

                self.signals.finished.emit()

                break


    def close(self):

        self.__net.end_process()



class RunnerSignal(QObject):

    finished = pyqtSignal()



class Mnist(Process):

    def __init__(self, queue: Queue):

        Process.__init__(self)

        self.__queue = queue


    def run(self):

        mnist = tf.keras.datasets.mnist  # 28x28 Bilder hangeschriebener Ziffern von 0-9


        (x_train, y_train), (x_test, y_test) = mnist.load_data()


        x_train = tf.keras.utils.normalize(x_train, axis=1)


        model   = tf.keras.models.Sequential()

        model.add(tf.keras.layers.Flatten())

        model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu))

        model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu))

        model.add(tf.keras.layers.Dense(10, activation=tf.nn.softmax))


        model.compile(optimizer="adam",

                      loss="sparse_categorical_crossentropy",

                      metrics=['accuracy'])


        model.fit(x_train, y_train, epochs=8)

        self.__queue.put(NetSignal.finished)

        self.__queue.close()


    def end_process(self):

        self.terminate()

        self.__queue.put(NetSignal.finished)

        self.__queue.close()

        


class NetSignal:

    finished = "finished"



if __name__ == "__main__":

    main_thread = QApplication(argv)

    main_window = Window()

    main_window.show()

    exit(main_thread.exec())



查看完整回答
反對 回復 2023-08-22
  • 1 回答
  • 0 關注
  • 119 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號