暂停QThread的run方法来测试它

时间:2015-02-25 15:16:15

标签: python pyqt python-requests qthread

我创建一个这样的Worker对象:

from PyQt4 import QtSql, QtCore
from requests_futures.sessions import FuturesSession


class Worker(QtCore.QThread):

    def __init__(self):

        QtCore.QThread.__init__(self)

        self.exiting = False
        self.list_urls = # Urls coming from somewhere

        # List to store the urls of the pages to request
        self.list_futures_urls = []


    def __del__(self):

        """Method to destroy the thread properly"""

        self.exiting = True
        self.wait()


    def run(self):

        """Main function. Starts the real business"""
        print(self.exiting) # -> True !!!!!

        session = FuturesSession(max_workers=10)

        for url in self.list_urls:

            future = session.get(url)
            future.add_done_callback(completeData)
            self.list_futures_urls.append(future)

        # HERE !!!!! WHY ?
        print(self.exiting) # -> True
        self.exiting = False
        print(self.exiting) # -> False

        while not self.exiting:
            self.sleep(20000)
            # self.wait()


    def completeData(self):

        total_futures = self.list_futures_urls

        # Checking if all the futures have started and finished
        if len(total_futures) !=  len(self.list_urls):
            return
        else:
            states_futures = []
            for result in total_futures:
                states_futures.append(result.done())

            if False not in states_futures:
                self.exiting = True
                print("boum")

如您所见,我的worker是一个线程,并启动异步请求Session。因此run()方法启动异步Web请求,然后完成。在这个阶段,线程通常发送"完成"信号。但是异步Web请求当然没有完成。

我该怎样做才能阻止"完成"信号,直到所有异步Web请求完成?

我在run()方法结束时尝试使用wait(),但是得到了:

QThread::wait: Thread tried to wait on itself

我也尝试过sleep(),但没有结果,'完成了'信号仍在发出。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我无法重现,但我有一些可能有帮助的注释:

可能发生的事情是所有异步任务在解释器到达行之前完成:

 while not self.exiting:

您假设异步调用会在所有处理完成之前为您提供足够的时间来到达while语句。

另一方面,由于您使用的是QtCore.QThread,因此您不需要控制变量来知道何时停止,您可以使用以下方法之一停止线程:QThread.exit,{{ 3}}或QThread.quit,请注意不推荐的最后一个。

关于self.exiting成为True,这非常罕见,我不得不说,但是如果不执行行self.exiting = True我就不会发生这种情况(查看您的代码)我建议在那里设置断点并查看callstack以跟踪导致该行被执行的调用路径。

另一个想法是设置QThread.terminate以查看self.exiting的值何时发生变化。

可行解决方案:

class Worker(QtCore.QThread):
    # I don't test this code, is just for show
    # the way to go.

    def __init__(self):

        QtCore.QThread.__init__(self)
        self.list_urls = # Urls coming from somewhere
        self.list_futures_urls = []

    def run(self):

        """Main function. Starts the real business"""
        session = FuturesSession(max_workers=10)

        for url in self.list_urls:
            future = session.get(url)
            future.add_done_callback()
            self.list_futures_urls.append(future)

        while (True):
            # You could add some sleep here in order to create a small delay between iterations.
            # WARNING: You have to aware of the posibility that a result.get() call never returns True,
            #          in that this code (as well as yours) will run into an infinite loop/thread.
            results = [result.done() for result in  self.list_futures_urls]
            if (False not in results):
                self.exit()

        # Callback removed from this code since the only purpose of 
        # it was to end the thread when all task get done.