Threads not working simultaneously
-
I am trying to get 2 threads to work simultaneously.
import sys from PyQt5 import QtWidgets from PyQt5.QtCore import QObject, QThread class Worker(QObject): def run(self, str): while True: print(str) class ThreadController(): def __init__(self): # Thread 1 self.thread = QThread() self.worker = Worker() self.worker.moveToThread(self.thread) self.thread.started.connect(lambda:self.worker.run('worker1')) self.thread.start() # Thread 2 self.thread2 = QThread() self.worker2 = Worker() self.worker2.moveToThread(self.thread2) self.thread2.started.connect(lambda:self.worker2.run('worker2')) self.thread2.start() if __name__=='__main__': app = QtWidgets.QApplication(sys.argv) thread = ThreadController() sys.exit(app.exec_())
This should print "worker1" and "worker2". However I'm only seeing the output "worker1".
How can I fix this? -
It could be that threads run OK but the
print()
is so much flooded with messages from the first thread that it can't display any of thread2 messages.Try introducing some small
sleep
to your thread loop, to giveprint
some space to breathe. -
I've tried that, but worker2 still doesn't print anything.
class Worker(QObject): def run(self, str): while True: print(str) time.sleep(1)
@fizdiz
I don't know, but start out with a bit more debugging:- Put in
print()
statement immediately aboveself.thread2.start()
. Does it get hit? - Remove
while True
inWorker
so it justprint(str)
once. Do you see both threads run? - Replace
while True
withfor i in range(100)
. Do you see thread2 messages as well as thread1 ones now?
- Put in
-
@fizdiz
I don't know, but start out with a bit more debugging:- Put in
print()
statement immediately aboveself.thread2.start()
. Does it get hit? - Remove
while True
inWorker
so it justprint(str)
once. Do you see both threads run? - Replace
while True
withfor i in range(100)
. Do you see thread2 messages as well as thread1 ones now?
@JonB
I've done the things you suggested and it seems that thread2 is actually executed, but the print statements of worker2 are printed only after worker1 stops printing.However, this solves my problem as it has been shown that it's not a problem with the threads but with my code which is running in the threads.
Thanks!
- Put in
-
@JonB
I've done the things you suggested and it seems that thread2 is actually executed, but the print statements of worker2 are printed only after worker1 stops printing.However, this solves my problem as it has been shown that it's not a problem with the threads but with my code which is running in the threads.
Thanks!
@fizdiz
This implies that Python'stime.sleep(1)
in a thread does not "relinquish control", such that another thread can run. Which I find surprising as I have seen other people use that from Python threads.I am not a Python super-expert, but I know there is a "wrinkle" with multiple threads in Python (which does not arise in C++). Python's interpreter, named "GIL", is required to execute all Python code. When multi-threading, only one instance of the GIL can run at any one time, i.e. the Python interpreter is not multi-thread-re-entrant. It looks like
time.sleep()
is still executed by the GIL such that it does not allow another thread to get the GIL. You may have to investigate further..... -
@fizdiz
This implies that Python'stime.sleep(1)
in a thread does not "relinquish control", such that another thread can run. Which I find surprising as I have seen other people use that from Python threads.I am not a Python super-expert, but I know there is a "wrinkle" with multiple threads in Python (which does not arise in C++). Python's interpreter, named "GIL", is required to execute all Python code. When multi-threading, only one instance of the GIL can run at any one time, i.e. the Python interpreter is not multi-thread-re-entrant. It looks like
time.sleep()
is still executed by the GIL such that it does not allow another thread to get the GIL. You may have to investigate further.....@JonB said in Threads not working simulataneously:
@fizdiz
This implies that Python'stime.sleep(1)
in a thread does not "relinquish control", such that another thread can run. Which I find surprising as I have seen other people use that from Python threads.I am not a Python super-expert, but I know there is a "wrinkle" with multiple threads in Python (which does not arise in C++). Python's interpreter, named "GIL",
GIL is an acronym of Global Interpreter Lock. A python statement can change global state, including redefining functions. The widely used CPython (aka $PATH/python most of the time) implementation simplifies the the situation by only allowing one thread to run at a time. A thread may yield between statements (or maybe it's a sequence point), but nothing interpreted runs simultaneously.
PyQt, and probably PySide release the lock when calling native/C++ code. I think the lesson is clear. Prefer C++ =-)
-
@JonB said in Threads not working simulataneously:
@fizdiz
This implies that Python'stime.sleep(1)
in a thread does not "relinquish control", such that another thread can run. Which I find surprising as I have seen other people use that from Python threads.I am not a Python super-expert, but I know there is a "wrinkle" with multiple threads in Python (which does not arise in C++). Python's interpreter, named "GIL",
GIL is an acronym of Global Interpreter Lock. A python statement can change global state, including redefining functions. The widely used CPython (aka $PATH/python most of the time) implementation simplifies the the situation by only allowing one thread to run at a time. A thread may yield between statements (or maybe it's a sequence point), but nothing interpreted runs simultaneously.
PyQt, and probably PySide release the lock when calling native/C++ code. I think the lesson is clear. Prefer C++ =-)
-
@jeremy_k
Yes, but unfortunately I don't see how this tells us why OP says second thread does not run/print while first thread callstime.sleep()
, which I have seen others use in Python threads so one would have thought would yield and work.....@JonB said in Threads not working simulataneously:
@jeremy_k
Yes, but unfortunately I don't see how this tells us why OP says second thread does not run/print while first thread callstime.sleep()
, which I have seen others use in Python threads so one would have thought would yield and work.....This might be actually unrelated to Python. Remember that
print
is a system call and OS has to synchronize it between many threads and many processes. I've seen many situations where even C++ & Qt would also only print from one thread and only display the remaining messages after you close the app. -
@jeremy_k
Yes, but unfortunately I don't see how this tells us why OP says second thread does not run/print while first thread callstime.sleep()
, which I have seen others use in Python threads so one would have thought would yield and work.....@JonB I wasn't addressing OP's issue, but rather the python interpreter is called "GIL" comment, and implications the global lock has on parallelism.
To the best of my knowledge, python makes no promises about fairness of thread scheduling. I try to code my routines to finish their computation and get out of the way rather than busy wait.
Edit: The same goes for C++.
-
@jeremy_k
Yes, but unfortunately I don't see how this tells us why OP says second thread does not run/print while first thread callstime.sleep()
, which I have seen others use in Python threads so one would have thought would yield and work.....@JonB I still don't know why the print messages are not printed simultaneously. It seems like the program waits for the loop in one thread to finish, before starting the loop in the next thread.
I don't think that it has to do with the fact that
print
is a system call. I have written similar code which starts a loop in a thread to update a button in a GUI, but the GUI doesn't show until the thread is finished.It also doesn't seem to be an issue with Python's built-in
time.sleep()
, as I get the same issue with Qt'sQThread.sleep()
So I still don't know how to fix the above issue.