程序必须等待两个线程(SQL查询执行)完成

时间:2019-08-21 02:48:01

标签: python python-3.x python-multithreading qthread pyside2

我有一个与数据库表值进行比较的程序,并且已经在PyQt5中创建了一个GUI。我创建了两个线程,一个用于查询每个表,然后程序必须等待两个线程完成。我的下面的代码

from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from Main_interface import Ui_mainWindow
import pandas as pd


class mainWindow(QtWidgets.QMainWindow, Ui_mainWindow):

  sqlClicked1 = QtCore.Signal(str)
  sqlClicked2 = QtCore.Signal(str)

  def __init__(self, parent=None):
    super(mainWindow, self).__init__(parent)
    self.setupUi(self)

    self.thread = QtCore.QThread(self)
    self.thread.start()
    self.obj = Worker()
    self.obj.moveToThread(self.thread)
    self.sqlClicked.connect(self.obj.runsql_MC)
    self.sqlClicked1.connect(self.obj.runsql_IRI)
    self.obj.error.connect(self.on_error)


 def run_report(self):
    sqlquery1 = "Select * from table1"
    sqlquery2 = "Select * from table2"

    df1 = self.sqlClicked1.emit(sqlquery1)
    df2 = self.sqlClicked2.emit(sqlquery2)

    self.sqlClicked1.finished.connect(self.on_finished)
    self.sqlClicked2.finished.connect(self.on_finished)

    print("SQL execution is done")

    #Then i am calling function to compare two dataframes


class Worker(QtCore.QObject):
   finished = QtCore.Signal()
   result = QtCore.Signal(object)

   @QtCore.Slot(str)
   def runsql_MC(self, sqlquery_MC):
     print("Thread1 is working")
     try:
        df1 = pd.read_sql(sql=sqlquery_MC, con=cnxn)
     except:
        traceback.print_exc()
     else:
        self.signals.result.emit(df1)  # Return the result of the processing
     finally:
        self.signals.finished.emit()  # Done

  @QtCore.Slot(str)
  def runsql_IRI(self, sqlquery_IRI):
    print("Thread2 is working")
    try:
        df2 = pd.read_sql(sql=sqlquery_IRI, con=cnxn)
    except:
        traceback.print_exc()
    else:
        self.signals.result.emit(df2)  
    finally:
        self.signals.finished.emit()  


if __name__ == '__main__':
  import sys
  app = QtWidgets.QApplication(sys.argv)
  my_app = mainWindow()
  my_app.show()
  sys.exit(app.exec_())

self.sqlClicked1.emit(sqlquery1)self.sqlClicked2.emit(sqlquery2)正在调用相应的线程runsql_MC()runsql_IRI。然后,我需要等到两个线程完成后才能开始比较过程。目前还没有发生。

2 个答案:

答案 0 :(得分:2)

尽管您的代码不是MRE,但请显示您对各种概念的了解。

  • 发射信号并不意味着获得数据,因为它将异步发送。

  • 在您的代码中,即使您调用2个查询也不意味着每个线程都在不同的线程上运行,因为工作进程位于单个线程中。

  • 您的runsql_MC和runsql_IRI方法是多余的,因为它们是同一事物的模板。

  • 除了其他错误(例如,没有名为sqlClicked的对象/信号)之外,您还没有声明对象信号等。

这个想法是让一个工人生活在每个查询的不同线程中,并创建一个类来处理等待数据的工人,并在他们完成工作时消除他们。

from functools import partial
import sqlite3
import pandas as pd
from PySide2 import QtCore, QtGui, QtWidgets


class Worker(QtCore.QObject):
    finished = QtCore.Signal()
    result = QtCore.Signal(object)

    @QtCore.Slot(str)
    def runsql(self, query):
        cnxn = sqlite3.connect("test.db")
        print("Thread1 is working")
        try:
            df1 = pd.read_sql(sql=query, con=cnxn)
        except:
            traceback.print_exc()
        else:
            self.result.emit(df1)  # Return the result of the processing
        finally:
            self.finished.emit()  # Done


class SqlManager(QtCore.QObject):
    results = QtCore.Signal(list)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.workers_and_threads = {}
        self.dataframes = []

    def execute_queries(self, queries):
        for query in queries:
            thread = QtCore.QThread(self)
            thread.start()
            worker = Worker()
            worker.result.connect(self.onResults)
            worker.moveToThread(thread)
            self.workers_and_threads[worker] = thread
            # launch task
            wrapper = partial(worker.runsql, query)
            QtCore.QTimer.singleShot(0, wrapper)

    @QtCore.Slot(object)
    def onResults(self, result):
        worker = self.sender()
        thread = self.workers_and_threads[worker]
        thread.quit()
        thread.wait()
        del self.workers_and_threads[worker]
        worker.deleteLater()
        self.dataframes.append(result)
        if not self.workers_and_threads:
            self.results.emit(self.dataframes)
            self.dataframes = []


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.push_button = QtWidgets.QPushButton("Run Report")
        self.push_button.clicked.connect(self.run_report)
        self.setCentralWidget(self.push_button)

        self.manager = SqlManager(self)
        self.manager.results.connect(self.onResults)

    @QtCore.Slot()
    def run_report(self):
        sqlquery1 = "Select * from table1"
        sqlquery2 = "Select * from table2"
        queries = [sqlquery1, sqlquery2]
        self.manager.execute_queries(queries)
        self.push_button.setEnabled(False)

    @QtCore.Slot(list)
    def onResults(self, dataframes):
        print(dataframes)
        self.push_button.setEnabled(True)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    my_app = MainWindow()
    my_app.show()
    sys.exit(app.exec_())

答案 1 :(得分:1)

我不太确定它是否用您的代码编写,但是您是否曾经使用过screens/HomeScreen.js语句来等待这些线程结束?当您从def __init__()类唤醒mainWindow方法内的这两个线程时,应该使用它