Skip to content
  • Kategorien
  • World
  • Aktuell
  • Tags
  • Beliebt
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
linux-nerds.org

linux-nerds.org

  1. Übersicht
  2. Linux
  3. Python3
  4. PyQt5 - QThread

PyQt5 - QThread

Geplant Angeheftet Gesperrt Verschoben Python3
pyqt5python3
3 Beiträge 1 Kommentatoren 309 Aufrufe
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • FrankMF Offline
    FrankMF Offline
    FrankM
    schrieb am zuletzt editiert von FrankM
    #1

    Eines der Geheimnisse, was mich schon was länger beschäftigt ist, wie man parallele Prozesse mit Python verwaltet. Dazu findet man viele Beispiele und man rätselt und rätselt.....

    Mal gehen die Beispiele nicht, mal versteht man sie nicht. Dabei habe ich nur was gesucht, was mir möglichst einfach darstellt, wie man so was grundsätzlich aufbaut. Der Rest kommt dann mit der Zeit, wenn ich lange genug damit herumgespielt habe 😊

    Ok, warum das Ganze? Ich habe in meinem Restic UI Prozesse, die was länger dauern. Ich möchte dem Anwender das signalisieren, mittels einem waitingspinnerwidget. Ok, so weit hatte ich das auch hinbekommen, nur was mache ich mit einem Ergebnis in diesem Prozess? Das muss ja irgendwie zurück 🤔

    Ich habe dann diese Code hier gefunden und zum Laufen bekommen. YEAH

    #!/usr/bin/env python3
    
    from PyQt5.QtCore import QObject, QThread
    from PyQt5.QtCore import pyqtSlot, pyqtSignal
    from PyQt5.QtWidgets import QMainWindow
    
    import sys
    import time
    from PyQt5.QtWidgets import QApplication
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            print("Base init")
    
            self.thread = QThread()
            self.w = Worker()
            self.w.finished[str].connect(self.onFinished)
            self.w.moveToThread(self.thread)
            self.thread.started.connect(self.w.work)
            self.thread.start()
    
        @pyqtSlot(str)
        def onFinished(self, i):
            #print("Base caught finished, {}".format(i))
            print("Worker end", i)
    
    class Worker(QObject):
        finished = pyqtSignal(str)
    
        def __init__(self):
            print("Worker init")
            super().__init__()
    
        def work(self):
            print("Worker work")
            time.sleep(5)
            self.finished.emit('TEXT')
    
    if __name__ == "__main__":
    
        app = QApplication(sys.argv)
        w = MainWindow()
        w.show()
    
        sys.exit(app.exec_())
    

    Das ist jetzt nicht so verdammt schwer, ein wenig hat man ja schon gelernt. Es geht ein Fenster auf, der Hauptprozess startet den Worker als eigenen Prozess. Der macht nicht viel, als 5 Sekunden zu warten und dann wenn er beendet wird, sendet er ein Signal an den Hauptprozess def onFinished(self, i): welcher dann eine Meldung in die Konsole ausgibt. Nix besonderes, aber für mich ein Ansatz meine Aufgabe zu lösen.

    Quelle: https://stackoverflow.com/questions/29243692/pyqt5-how-to-make-qthread-return-data-to-main-thread

    Im Fediverse -> @FrankM@nrw.social

    1. NanoPi R5S
    2. Quartz64 Model B, 4GB RAM
    3. Quartz64 Model A, 4GB RAM
    4. RockPro64 v2.1
    1 Antwort Letzte Antwort
    0
    • FrankMF Offline
      FrankMF Offline
      FrankM
      schrieb am zuletzt editiert von
      #2

      Das Thema muss sitzen, also versuche ich das etwas zu vertiefen. Gestern habe ich viel Stunden damit verbracht, mein Restic UI auf das waitingspinnerwidget umzubauen. Bis auf eine Funktion, die heute noch dran kommt, habe ich alles hinbekommen 🙂 Aber, wie immer habe ich danach Fragen. Ok, fangen wir mal an.

      @pyqtSlot(str)
      def onFinished(self, i):
          #print("Base caught finished, {}".format(i))
          print("Worker end", i)
      

      Wenn wir uns den Code anschauen, kommt die Frage auf, was macht @pyqtSlot(str) ? Ich probiere viel aus, also hatte ich das in meinem Code auskommentiert und mich gewundert, warum das immer noch funktioniert!? Ok, also Dokumentation lesen.

      Support for Signals and Slots — PyQt Documentation v5.15.7

      favicon

      (www.riverbankcomputing.com)

      Connecting a signal to a decorated Python method also has the advantage of reducing the amount of memory used and is slightly faster.

      Das klärt meine Frage aber immer noch nicht komplett. Auf stackoverflow.com, das folgende gefunden.

      For your case consider it as a good practice - denoting a method as a slot for some signal.

      Just a moment...

      favicon

      (stackoverflow.com)

      Also muss ich mir jetzt merken, das es weniger Speicher verbraucht und etwas schneller ist. Gut, und es ordentlicher Programmierstil(?), wenn ich die Funktionen als abhängig von Signalen kennzeichne!? Ich denke, so passt es ganz gut.

      Sehr gute Anleitungen zum Thema findet man auch immer wieder auf realpython.com. Hier z.B. zum Thema QThread. Anhand des Beispieles habe ich meinen ersten QThread heute folgendermaßen dokumentiert.

          "First Thread with documentation"
          # Worker for restic_stats
          # Create a QThread object
          self.thread = QThread()
          # Create a worker object
          self.worker1 = Worker()
          # Move worker to the thread
          self.worker1.moveToThread(self.thread)
          # Connect signals and slots
          self.thread.started.connect(self.worker1.run)
          self.worker1.stats_finished[str].connect(self.restic_stats_finished)
          self.worker1.stats_error[str].connect(self.restic_stats_error)
          "First thread end"
      

      Dann stand ich sehr schnell vor dem Problem, was mache ich bei der nächsten Funktion, die einen QThread braucht?

          # Worker for restic_backup
          self.thread2 = QThread()
          self.worker2 = Worker2()
          self.worker2.moveToThread(self.thread2)
          self.thread2.started.connect(self.worker2.run)
          self.worker2.backup_finished[str].connect(self.restic_backup_finished)
          self.worker2.backup_error[str].connect(self.restic_backup_error)
      

      Ok, das war jetzt nicht so wirklich schwierig.

      Im Fediverse -> @FrankM@nrw.social

      1. NanoPi R5S
      2. Quartz64 Model B, 4GB RAM
      3. Quartz64 Model A, 4GB RAM
      4. RockPro64 v2.1
      1 Antwort Letzte Antwort
      0
      • FrankMF Offline
        FrankMF Offline
        FrankM
        schrieb am zuletzt editiert von FrankM
        #3

        Und hier mal ein komplettes Beispiel.

        class Worker

        Wir legen den Worker an, das ist der Prozess der die Arbeit macht und etwas länger braucht.

        class Worker(QObject):
        
            """ Worker Class for Rest function stats"""
            stats_finished = pyqtSignal(str)
            stats_error = pyqtSignal(str)
        
            def __init__(self):
                super().__init__()
        
            def run(self):
                # Restic function
        
            try:
                # long running task
            except Exception:
                # Process don't successful, send signal
                self.stats_error.emit(result.stderr)
            else:
                # Process successful, send signal
                self.stats_finished.emit(result.stdout)
            finally:
                pass
        

        in class MainWindow

        class MainWindow(QMainWindow):
            def __init__(self):
            super().__init__()
        
            "First Thread with documentation"
            # Worker for restic_stats
            # Create a QThread object
            self.thread = QThread()
            # Create a worker object
            self.worker1 = Worker()
            # Move worker to the thread
            self.worker1.moveToThread(self.thread)
            # Connect signals and slots
            self.thread.started.connect(self.worker1.run)
            self.worker1.stats_finished[str].connect(self.restic_stats_finished)
            self.worker1.stats_error[str].connect(self.restic_stats_error)
            "First thread end"
        
            ###############################################
            # Process for restic_stats is finished
            ###############################################
        
            @pyqtSlot(str)
            def restic_stats_finished(self, i):
                # Signal from worker thread without an error
        
            Spinner.stop(self)
        
            self.thread.quit()
        
            ###############################################
            # Process for restic_stats when get an error
            ###############################################
        
            @pyqtSlot(str)
            def restic_stats_error(self, i):
                # Signal from worker thread with an error!
        
                Spinner.stop(self)
        

        Funktion restic_stats

        def restic_stats(self):
            # we start the worker thread
            self.thread.start()
        
            # we start waitingspinnerwidget
            Spinner.start(self)
        

        Ich wollte gerade schreiben, das folgendes sehr wichtig ist

        self.thread.quit()
        

        da fällt mir ein Fehler auf. Kurz ausprobiert und bingo, wenn der Prozess einen Error triggert, muss natürlich auch der Prozess beendet werden. Wenn man das nicht macht, macht das Programm nicht das was es soll. Der Grund ist, das der Prozess einfach immer weiter läuft. Er MUSS beendet werden. Ich gehe dann mal in meinem Programm alles ändern 🙂

        Ok, jetzt geht die Funktion auch zweimal hintereinander und gibt auch ordentlich den Fehler aus.

        Fazit

        Ich habe wieder sehr viel gelernt und hoffe das ich es auch richtig verstanden habe 😉 Hoffe das es dem ein oder anderen Anfänger hilft. Und falls hier ein Profi mitliest und hier Blödsinn steht bitte ich um einen Kommentar, damit ich das ändern kann. Es steht schon genug Blödsinn im Netz 🙂

        Im Fediverse -> @FrankM@nrw.social

        1. NanoPi R5S
        2. Quartz64 Model B, 4GB RAM
        3. Quartz64 Model A, 4GB RAM
        4. RockPro64 v2.1
        1 Antwort Letzte Antwort
        0
        Antworten
        • In einem neuen Thema antworten
        Anmelden zum Antworten
        • Älteste zuerst
        • Neuste zuerst
        • Meiste Stimmen


        • FrankMF

          PyQt6 - QRegularExpressionValidator

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 pyqt6 python3
          1
          0 Stimmen
          1 Beiträge
          664 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Python3 - PyQt6 installieren

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 pyqt6 python3
          1
          0 Stimmen
          1 Beiträge
          438 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Restic UI - QThread

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Restic UI restic-ui python3
          1
          0 Stimmen
          1 Beiträge
          159 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Django - Webframework

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 django python3
          1
          2
          0 Stimmen
          1 Beiträge
          148 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Restic UI - Documentation

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Restic UI restic-ui python3 pyqt5
          1
          1
          0 Stimmen
          1 Beiträge
          359 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Python3 - QInputDialog

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 python3
          1
          1
          0 Stimmen
          1 Beiträge
          199 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Python3 - subprocess.Popen

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 restic python3
          1
          0 Stimmen
          1 Beiträge
          346 Aufrufe
          Niemand hat geantwortet
        • FrankMF

          Python3 - zwei Webseiten als Empfehlung

          Beobachtet Ignoriert Geplant Angeheftet Gesperrt Verschoben Python3 pyqt5 python3
          1
          0 Stimmen
          1 Beiträge
          202 Aufrufe
          Niemand hat geantwortet
        Powered by NodeBB | Contributors
        © 2022 frank-mankel.de
        Fediverse
        • Anmelden

        • Du hast noch kein Konto? Registrieren

        • Anmelden oder registrieren, um zu suchen
        • Erster Beitrag
          Letzter Beitrag
        0
        • Kategorien
        • World
        • Aktuell
        • Tags
        • Beliebt