I have the following code:
from PySide.QtCore import *
import time
class GUI(object):
IDLIST = [i for i in xrange(20)]
UNUSEDIDS = [i for i in xrange(20)]
def __init__(self):
print "GUI CLASS INITIALIZED!"
worker = Worker()
worker2 = Worker2()
threadpool = QThreadPool()
threadpool.setMaxThreadCount(10)
for i in xrange(5):
#Alternate between the two
#threadpool.start(worker)
#worker2.start()
#classmethod
def delegator(self):
"""Irrelevant to the question, I need this method for something else"""
USEDIDS = []
toUse = self.UNUSEDIDS[0]
USEDIDS.append(toUse)
self.UNUSEDIDS.pop(0)
return toUse
class Worker(QRunnable):
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
def run(self):
#idInUse = getattr(GUI, "delegator")
idInUse = GUI.delegator()
print "Hello world from QRunnable", idInUse
#time.sleep(5)
class Worker2(QThread):
def __init__(self, parent=None):
super(Worker2, self).__init__(parent)
def run(self):
idInUse = GUI.delegator()
print "Hello world from QThread", idInUse
s = time.time()
GUI()
print "Done in %s" % ((time.time()-s) * 1000)
I think the desired effect is obvious from the code. I want the "Hello world from QThread/QRunnable " to be shown. Since I am writing a multi-threaded application, in my GUI __init__ part I have the loop that starts concurrent threads.
The thing is that, with QRunnable it works just fine. All the 5 threads I specified get executed at once, concurrently. With QThread, however, that is not the case. Instead, I get the following error:
QThread: Destroyed while thread is still running
And it is not executed at all.
Normally I would not at all mind using the QRunnable, however, it does not derive from QObject (so I can't directly emit signals though I can construct a QObject() within it) and also it does not have the .stop() method which I badly need. Googling revealed that there is no way to stop a QRunnable from executing? On the other hand, QThread has both of these methods that I need.
So I guess my question is either how to make multiple same QThreads run concurrently, or how to terminate an execution of a QRunnable?
(also please bear in mind that the python's built-in threading module is out of the question)
The QThread: Destroyed while thread is still running-exception happens because you never wait for your threads to finish, and you don't keep any reference to them (neither to worker, worker2 or threadpool, so when your __init__ finishes it gets destroyed.
if you keep a reference to this objects, then is should work:
def __init__(self):
print "GUI CLASS INITIALIZED!"
self.worker = Worker()
self.worker2 = Worker2()
self.threadpool = QThreadPool()
self.threadpool.setMaxThreadCount(10)
for i in xrange(5):
#Alternate between the two
self.threadpool.start(worker)
# this is wrong, by the way!
# you should create 5 workers, not call start 5 times...
self.worker2.start()
and calling the wait/waitForDone methods on the thread/pool is even better.
For a QThreadPool this implicily happens when it's (C++) destructor is called. If that wasn't the case, then your program wouldn't have worked with QRunnables in the first place eiter. For the QThread nothing like this happens and it's even mentioned that it will probably result in a crash. So it's better to explicitly wait for the threads to finish...
also, i hope you already know this
Related
This class suppose to handle a long task in a separate thread.
Despite moving my object to a new thread, and using queued connection, the signal is handled at the main gui thread instead of self.thread. The main gui thread is the thread that did called startit of course..
This is the code:
class DoLongProcess(QObject):
def __init__(self,task):
QObject.__init__(self)
self._task=task
self._realtask=None
self.thread = QThread()
self.moveToThread(self.thread)
self.thread.started.connect(self.run,Qt.QueuedConnection)
#Slot()
def run(self):
self._realtask()
def startit(self,*params):
self._realtask= partial(self._task,*params)
self.thread.start()
I use pyside6. I tried to to split __init__ into two methods and moving the thread from outside. Also tried without the QueuedConnection attribute (which suppose to do this exactly). None of this had an effect.
Do you know why it doesn't work as expected?
I thought I've read it all about threading in Qt, but apparently I'm getting it wrong. I'm stuck with this stuff for some time now, so I would really appreciate your help a lot.
So, I created a class that starts a thread in its __init__ method:
class MyClass(object):
def __init__(self):
(...)
self.thread = QtCore.QThread(parent)
worker = Worker()
QtCore.QObject.connect(self.thread, QtCore.SIGNAL('started()'), worker,
QtCore.SLOT('doWork()'))
QtCore.QObject.connect(worker, QtCore.SIGNAL('finished()'), self.thread,
QtCore.SLOT('quit()'))
QtCore.QObject.connect(worker, QtCore.SIGNAL('finished()'), worker,
QtCore.SLOT('deleteLater()'))
QtCore.QObject.connect(self.thread, QtCore.SIGNAL('finished()'),
self.thread, QtCore.SLOT('deleteLater()'))
worker.moveToThread(self.thread)
self.thread.start()
Worker class looks like that:
class Worker(QtCore.QObject):
(some signals)
def doWork(self):
print "doing my work"
The problem is that my doWork slot is never executed, although the thread is running.
After creating instance of MyClass, let's say:
obj = MyClass()
I can call:
obj.thread.isRunning()
which returns True.
I assume that signal 'started' is not emitted, because of instantly exiting the method where thread was created (when I add sleep after starting thread, it enters doWork slot). I wonder how such situation should be handled properly.
Please let me know if I did not explain my problem clearly.
Thank you all for help in advance.
Your worker is being garbage collected after the MyClass constructor returns. Make worker a member of MyClass so that it persists beyond the constructor.
self.worker = Worker()
I have a class function in python.
I run the class in many different instances
class worker():
def__init__(x,x)
def run():
instance1 = worker(x,x)
instance1.run()
instance2 = worker(x,x)
instance2.run()
The problem is if first instance1 encounter thread.sleep() it affects the other instance2. How do i make them independent. Better if without multi-process Thank you!
Different example:
__author__ = 'user'
import time
class test():
def __init__(self, message):
self.message=message
def run(self):
while True:
print self.message
time.sleep(5)
if __name__ == '__main__':
test1 = test("PRINT-1")
test1.run()
test2 = test("PRINT-2")
test2.run()
you can use Celery for run parallel tasks. It's easy to implement.
See an example:
import time
from celery import task
#task
def make_task():
time.sleep(5)
return True
def execute_tasks():
result = group([make_task.s(), make_task.s()]).apply_async() # Execute tasks
print result.get() # Print the result
It looks like you're half-followed a tutorial on parallel code. Nothing in your current test class will cause it to run in parallel, but with just some minor tweaks you can do so with either threads or processes.
Here's a version that makes the class inherit from threading.Thread:
import threading
import time
class TestThreaded(threading.Thread):
def __init__(self, x, y):
super().__init__()
self.x = x
self.y = y
def run(self):
for i in range(self.x):
time.sleep(self.y)
print((i+1)*self.y)
You can use it like this:
t0 = TestThreaded(8, 3)
t1 = TestThreaded(6, 4)
t0.start()
t1.start()
t0.join()
t1.join()
Both threads in this example will count to 24 over a span of 24 seconds. The first thread will count by threes, the second thread will count by fours. The timings will be closely synched at 12 and 24 seconds (depending on your computer's exact timings they may get printed on the same line).
Note that we're calling the start method inherited from the Thread class, not the run method we defined above. The threading code will call run for us, in the spawned thread.
You can get an equivalent multiprocessing version by using multiprocessing.Process as the base class instead of threading.Thread. The only difference is that you'll spawn child processes instead of child threads. For CPU limited work in Python, processes are better than threads because they're not limited by the Global Interpreter Lock, which makes it impossible for two threads to run Python code at the same time. The downside is higher overhead, both during startup, and when communicating between processes.
There are a lot of tutorials etc. on Python and asynchronous coding techniques, but I am having difficulty filtering the through results to find what I need. I am new to Python, so that doesn't help.
Setup
I currently have two objects that look sort of like this (please excuse my python formatting):
class Alphabet(parent):
def init(self, item):
self.item = item
def style_alphabet(callback):
# this method presumably takes a very long time, and fills out some properties
# of the Alphabet object
callback()
class myobj(another_parent):
def init(self):
self.alphabets = []
refresh()
def foo(self):
for item in ['a', 'b', 'c']:
letters = new Alphabet(item)
self.alphabets.append(letters)
self.screen_refresh()
for item in self.alphabets
# this is the code that I want to run asynchronously. Typically, my efforts
# all involve passing item.style_alphabet to the async object / method
# and either calling start() here or in Alphabet
item.style_alphabet(self.screen_refresh)
def refresh(self):
foo()
# redraw screen, using the refreshed alphabets
redraw_screen()
def screen_refresh(self):
# a lighter version of refresh()
redraw_screen()
The idea is that the main thread initially draws the screen with incomplete Alphabet objects, fills out the Alphabet objects, updating the screen as they complete.
I've tried a number of implementations of threading.Tread, Queue.Queue, and even futures, and for some reason they either haven't worked, or they have blocked the main thread. so that the initial draw doesn't take place.
A few of the async methods I've attempted:
class Async (threading.Thread):
def __init__(self, f, cb):
threading.Thread.__init__(self)
self.f = f
self.cb = cb
def run(self):
self.f()
self.cb()
def run_as_thread(f):
# When I tried this method, I assigned the callback to a property of "Alphabet"
thr = threading.Thread(target=f)
thr.start()
def run_async(f, cb):
pool = Pool(processes=1)
result = pool.apply_async(func=f, args=args, callback=cb)
I ended up writing a thread pool to deal with this use pattern. Try creating a queue and handing a reference off to all the worker threads. Add task objects to the queue from the main thread. Worker threads pull objects from the queue and invoke the functions. Add an event to each task to be signaled on the worker thread at task completion. Keep a list of task objects on the main thread and use polling to see if the UI needs an update. One can get fancy and add a pointer to a callback function on the task objects if needed.
My solution was inspired by what I found on Google: http://code.activestate.com/recipes/577187-python-thread-pool/
I kept improving on that design to add features and give the threading, multiprocessing, and parallel python modules a consistent interface. My implementation is at:
https://github.com/nornir/nornir-pools
Docs:
http://nornir.github.io/packages/nornir_pools.html
If you are new to Python and not familiar with the GIL I suggest doing a search for Python threading and the global interpreter lock (GIL). It isn’t a happy story. Generally I find I need to use the multiprocessing module to get decent performance.
Hope some of this helps.
Imagine I have this code (not written the actual timer yet):
class Timer(threading.Thread):
def __init__(self, seconds):
self.runTime = seconds
threading.Thread.__init__(self)
def run(self):
time.sleep(self.runTime)
#do some other function
print 'Finished'
t = Timer(60)
t.start()
Once the run() method has finished running, is there some way to stop the thread, and delete the class instance?
The run() method is everything that runs in a thread, so when it has finished nothing is running anymore. Then t.is_alive() will return False. You can then delete the instance using del t, but that will just remove your reference to it. The actual deleting will be done by garbage collector some time later.