Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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?


  • Moderators

    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 give print 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 above self.thread2.start(). Does it get hit?
    • Remove while True in Worker so it just print(str) once. Do you see both threads run?
    • Replace while True with for 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!



  • @fizdiz
    This implies that Python's time.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's time.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 calls time.sleep(), which I have seen others use in Python threads so one would have thought would yield and work.....


  • Moderators

    @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 calls time.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.



  • @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++.



  • @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's QThread.sleep()

    So I still don't know how to fix the above issue.


Log in to reply