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 ?
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.