I have a thread class, in it, I want to create a thread function to do its job corrurently with the thread instance. Is it possible, if yes, how ?
run function of thread class is doing a job at every, excatly, x seconds. I want to create a thread function to do a job parallel with the run function.
class Concurrent(threading.Thread):
def __init__(self,consType, consTemp):
# something
def run(self):
# make foo as a thread
def foo (self):
# something
If not, think about below case, is it possible, how ?
class Concurrent(threading.Thread):
def __init__(self,consType, consTemp):
# something
def run(self):
# make foo as a thread
def foo ():
# something
If it is unclear, please tell . I will try to reedit
Just launch another thread. You already know how to create them and start them, so simply write another sublcass of Thread and start() it along the ones you already have.
Change def foo() for a Thread subclass with run() instead of foo().
First of all, I suggest the you will reconsider using threads. In most cases in Python you should use multiprocessing instead.. That is because Python's GIL.
Unless you are using Jython or IronPython..
If I understood you correctly, just open another thread inside the thread you already opened:
import threading
class FooThread(threading.Thread):
def __init__(self, consType, consTemp):
super(FooThread, self).__init__()
self.consType = consType
self.consTemp = consTemp
def run(self):
print 'FooThread - I just started'
# here will be the implementation of the foo function
class Concurrent(threading.Thread):
def __init__(self, consType, consTemp):
super(Concurrent, self).__init__()
self.consType = consType
self.consTemp = consTemp
def run(self):
print 'Concurrent - I just started'
threadFoo = FooThread('consType', 'consTemp')
threadFoo.start()
# do something every X seconds
if __name__ == '__main__':
thread = Concurrent('consType', 'consTemp')
thread.start()
The output of the program will be:
Concurrent - I just startedFooThread - I just started
Related
I want to have a main program that works like a console from where I can call other processes (infinite loops) and kill them selectively whenever certain commands are entered.
For that I created this class:
class RunInThread(threading.Thread):
def __init__(self, function):
self.function = function
self.kill_pill = threading.Event()
threading.Thread.__init__(self)
def start(self): # This is controversial.
self.__init__(self.function)
threading.Thread.start(self)
def stop(self):
self.kill_pill.set()
def run(self):
while not self.kill_pill.is_set():
self.function()
The documentation for thread.Thread says that only the __init__() and run() methods should be overridden.
Is there any clear issue with my code? It works the way I intended but since it's going to be running for long periods of time I need to make sure I'm not creating any memory problems.
EDIT:
What about this solution?:
class StoppableThread(threading.Thread):
# threading.Thread class but can be stopped with the stop() method.
def __init__(self, function):
threading.Thread.__init__(self)
self.function = function
self.kill_pill = threading.Event()
def stop(self):
self.kill_pill.set()
def run(self):
while not self.kill_pill.is_set():
self.function()
class RunInThread():
def __init__(self, function, prnt=False):
self.function = function
self.running = False
self.prnt = prnt
def start(self):
if not self.running:
self.thread = StoppableThread(self.function)
self.thread.start()
self.running = True
else:
if self.prnt:
print('Thread already running.')
def stop(self):
self.thread.stop()
self.running = False
If you want to find out what things that could break, I'd suggest looking into the implementation of Thread class.
Among other things, Thread.__init__() initialises an Event() object to detect thread startup and shutdown, manages cleanup hooks/callbacks, some internal lock objects, and registers the thread to a list so you can introspect running threads. By calling Thread.__init__(), these variables gets reinitialised and screws up the internal mechanisms of many of these functionalities.
What could go wrong? I didn't test any of these, but from skimming through threading.py, these are likely some of the things that I expect could go wrong:
your python process now will be running a OS threads that doesn't show up in enumerate_thread()
multiple OS thread will now return the same Thread object when it calls current_thread(), which will likely also break threadlocal and anything that depends on threadlocal
Thread.join() depends on some internal locks, which likely would now become thread unsafe to call
Unhandled reception can go to the wrong exception hook handler
register_at_fork and shutdown handler likely will get confused
In other words, don't try to be sneaky. Create a new Thread object for each thread you want to start.
There's a good reason that the Thread class spent efforts trying to prevent you from accidentally calling start() twice. Don't try to subvert this.
I know this sounds a lot like this similarly-worded question, but there are differences, so bear with me.
I'm trying to create a reusable "Timer" class which calls a specified callback every N seconds, until you call stop. As inspiration, I used the link above, with a built-in event wrapped in a stop method. Here's how the basic class looks:
import time
import threading
from threading import Thread
from threading import Event
# Mostly inspired by https://stackoverflow.com/questions/12435211/python-threading-timer-repeat-function-every-n-seconds
class RepeatingTimer(Thread):
def __init__(self, interval_seconds, callback):
Thread.__init__(self)
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
self.setDaemon(True)
def start(self):
while not self.stop_event.wait(self.interval_seconds):
self.callback()
time.sleep(0) # doesn't seem to do anything
def stop(self):
self.stop_event.set()
Looks good, even includes time.sleep(0) based on this question.
It doesn't do what I thought; the call to start never seems to return or yield, ever. Consider this use-case:
def print_status(message):
print(message)
def print_r1():
print_status("R1")
def print_r2():
print_status("R2")
r1 = RepeatingTimer(1, print_r1)
r2 = RepeatingTimer(0.5, print_r2)
r1.start()
r2.start()
The call to r1.start never terminates. It continues on forever. The output on the console, after four seconds, is:
R1
R1
R1
R1
This prompted me to introduce the time.sleep(0) call, although that doesn't seem to do anything.
I also tried with and without self.setDaemon(True), but that also seems to have no effect.
I also tried converting this into two classes: one with just the event wrappers (a StoppableTimer class), and another that simply creates and recreates the StoppableTimer in the callback, but that doesn't work either. Here's what it looks like:
class StoppableTimer(Thread):
def __init__(self, interval_seconds, callback):
Thread.__init__(self)
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
self.setDaemon(True)
def start(self):
time.sleep(self.interval_seconds)
self.callback()
def stop(self):
self.stop_event.set()
class RepeatingTimer:
def __init__(self, interval_seconds, callback):
self.interval_seconds = interval_seconds
self.callback = callback
self.timer = StoppableTimer(interval_seconds, self.refresh_timer)
def start(self):
self.timer.start()
def stop(self):
self.timer.stop()
def refresh_timer(self):
self.stop()
self.callback()
self.timer = StoppableTimer(self.interval_seconds, self.refresh_timer)
self.timer.start()
I'm completely at a loss on how to make this work. I'm also mostly a beginner to Python, so please add sufficient explanation to your answer so I can grasp what the fundamental issue is.
I also read a bit about the Global Interpreter Lock on SO, but I don't understand how that could be an issue.
For reference, I'm running Python 3.6.3 on Ubuntu 17.10
Short answer :
Don't override start(). Override run() instead.
Long answer because you're asking for details :
With the class definition in your first snippet, you've created a class which inherits from Thread, however you've overriden the start() method supposed to start your thread by a new method which is looping until the stop_event is set, that is to say, the method supposed to actually start your thread doesn't do this anymore.
So, when you try to start your thread, you actually run the loop calling your callback function in your current and only thread. And since it's an infinite loop, your second "thread" is not started, and you have no way to "stop" it.
You mustn't override start (well not in this way). Instead, override the run method. This is the method that will be run by your thread when you start it.
Also, you should do super().__init__() instead of Thread.__init__(self). The first one is the proper way to call an inherited method in Python.
class RepeatingTimer(Thread):
def __init__(self, interval_seconds, callback):
super().__init__()
self.stop_event = Event()
self.interval_seconds = interval_seconds
self.callback = callback
def run(self):
while not self.stop_event.wait(self.interval_seconds):
self.callback()
def stop(self):
self.stop_event.set()
And with the functions you've defined you can do :
r1 = RepeatingTimer(1, print_r1)
r2 = RepeatingTimer(0.5, print_r2)
r1.start()
r2.start()
time.sleep(4)
r1.stop()
r2.stop()
Here is the relevant documentation for Thread.
I'd like to do some cleanup operations inside the object just before its destruction. In this case it would be close the connection to the database.
Here is what I'm already doing:
Worker class:
from PyQt5 import QtCore
from pymongo import MongoClient, ASCENDING
from time import sleep
class StatusWidgetWorker(QtCore.QObject):
ongoing_conversions_transmit = QtCore.pyqtSignal([list])
def __init__(self, mongo_settings):
super().__init__()
print("StatusWidget Worker init")
mongo_client = MongoClient([mongo_settings["server_address"]])
self.log_database = mongo_client[mongo_settings["database"]]
self.ongoing_conversions = mongo_settings["ongoing_conversions"]
def status_retriever(self):
print("mongo bridge()")
while True:
ongoing_conversions_list = []
for doc in self.log_database[self.ongoing_conversions].find({}, {'_id': False}).sort([("start_date", ASCENDING)]):
ongoing_conversions_list.append(doc)
self.ongoing_conversions_transmit.emit(ongoing_conversions_list)
sleep(2)
And the function that call the worker from an other class :
def status_worker(self):
mongo_settings = "dict parameter"
self.worker_thread_status = QtCore.QThread()
self.worker_object_status = StatusWidgetWorker(mongo_settings)
self.worker_object_status.moveToThread(self.worker_thread_status)
self.worker_thread_status.started.connect(self.worker_object_status.status_retriever)
self.worker_object_status.ongoing_conversions_transmit.connect(self.status_table_auto_updater)
self.worker_thread_status.start()
Here is what I already tried:
Define a __del__ function in the Worker class, this function is never called.
Define a function in the Worker class and then connect it to the destroyed signal with self.destroyed.connect(self.function). This function is again never called. I think this happen because the signal is emitted when the object is already destroyed, not before its destruction.
I'm really wondering on how to this, here are some parts of answer:
http://www.riverbankcomputing.com/pipermail/pyqt/2014-November/035049.html
His approach seems a bit hacky to me (no offense to the author, there is probably no simple answer) and I have signals & parameters to pass to the worker witch would make the ThreadController class messier.
I find this solution a bit hacky because you have to set up a Controller class to do the Worker class job
If nobody has an answer, I'll probably use the ThreadController class and post the result here.
thank you for reading :-)
The usual rule in python apply:
there is a module for that
the solution is to use the atexit module and register the cleanup function in the __init__ function.
Example:
import atexit
class StatusWidgetWorker(QObject):
def __init__(self):
super().__init__()
# code here
atexit.register(self.cleanup)
def cleanup(self):
print("Doing some long cleanup")
sleep(2)
self.bla = "Done !"
print(self.bla)
In another class:
self.workerThread = WorkerThread()
def startThread():
self.workerThread.setGameName("pizza")
self.workerThread.start()
QThread class:
class WorkerThread(QThread):
def _init_(self, parent = None):
super(WorkerThread, self)._init_(parent)
self.gameName = ""
def setGameName(self, currGameName):
self.gameName = currGameName
def run(self):
#do something with self.gameName
In main:
startThread()
startThread()
When I run this, it uses the gameName from the first call and not the second. The function calls seem interleaved. Can someone explain how Qthread works? How do i set a gameName for each individual function call of startThread()?
If start() is called twice on a QThread then the second call will do nothing if the thread is still running. It looks like there's a good chance this is what's happening, and if not then it's only due to luck.
I want to add a new method to a Thread subclass so I can tell my working thread to exit elegantly. Like this:
class MyThread(threading.Thread):
def __init__(self):
...
self.__stop_signal = False
self.__signal_lock = threading.Lock()
...
def run(self):
...
self.__signal_lock.acquire(True)
stop_signal = self.__stop_signal
self.__signal_lock.release()
if stop_signal:
return
...
def stop_elegantly(self):
self.__signal_lock.acquire(True)
self.__stop_signal = True
self.__signal_lock.release()
Then is it safe to do this?:
thread = MyThread()
thread.start()
...
thread.stop_elegantly()
Thanks.
Yes, it looks fine. In fact you could do it even more "elegantly" with:
def stop_elegantly(self):
with self.__signal_lock:
self.__stop_signal = True
Actually I don't think you even need a lock to access the member variable since there'll be a separate one allocated for each instance of your subclass. See this answer for example, which adds a stop() method to the threading.Thread subclass.
self.__signal_lock.acquire(True)
stop_signal = self.__stop_signal
self.__signal_lock.release()
The above code is in loop? If yes, I think it works well.