Pause the run method of a QThread to test it

JPFrancoia

I create a Worker object like this:

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")

As you can see, my worker is a thread, and starts an asynchronous requests Session. So the run() method starts the asynchronous web requests, and then is done. At this stage, the thread normally sends a "finished" signal. But the asynchronous web requests are of course not done.

What can I do to block the "finished" signal, until all the asynchronous web requests are done ?

I tried with wait() at the end of the run() method, but I get:

QThread::wait: Thread tried to wait on itself

I also tried with sleep(), but no result, the 'finished' signal is still emitted.

Any idea ?

Raydel Miranda

I could not reproduce that, but I have some annotations that might help:

What can be happening is all asynchronous tasks get done before the interpreter reach the line:

 while not self.exiting:

You're assuming that the asynchornous calls will give you enough time to reach the while statement before all processing get done.

On the other hand since you're using QtCore.QThread you don't need a control variable for knowing when to stop, you can just stop the thread using one of these: QThread.exit, QThread.quit or QThread.terminate, be aware the last it's not recomended.

About self.exiting becoming True, Its very rare, I have to say, but there is no way this can happend (looking at your code) without executing the line self.exiting = True I suggest set a breakpoint there and look the callstack for trace the path of calls that cause that line get executed.

Another idea is set a Hardware Breakpoit to see when the value of self.exiting get changed.

Posible Solution:

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.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related