How to keep track of thread progress in Python without freezing the PyQt GUI?

后端 未结 5 1224
余生分开走
余生分开走 2020-12-12 20:07

Questions:

  1. What is the best practice for keeping track of a tread\'s progress without locking the GUI (\"Not Responding\")?
  2. Gene
相关标签:
5条回答
  • 2020-12-12 20:17

    I recommend you to use Queue instead of signaling. Personally I find it a much more robust and understandable way of programming, because it's more synchronous.

    Threads should get "jobs" from a Queue, and put back results on another Queue. Yet a third Queue can be used by the threads for notifications and messages, like errors and "progress reports". Once you structure your code this way, it becomes much simpler to manage.

    This way, a single "job Queue" and "result Queue" can also be used by a group of worker threads, it routes all the information from the threads into the main GUI thread.

    0 讨论(0)
  • 2020-12-12 20:19

    You are always going to have this problem in Python. Google GIL "global interpretor lock" for more background. There are two generally recommended ways to get around the problem that you are experiencing: use Twisted, or use a module similar to the multiprocessing module introduced in 2.5.

    Twisted will require that you learn asynchronous programming techniques which may be confusing in the beginning but will be helpful if you ever need to write high throughput network apps and will be more beneficial to you in the long run.

    The multiprocessing module will fork a new process and uses IPC to make it behave as if you had true threading. Only downside is that you would need python 2.5 installed which is fairly new and inst' included in most Linux distros or OSX by default.

    0 讨论(0)
  • 2020-12-12 20:20

    If you want to use signals to indicate progress to the main thread then you should really be using PyQt's QThread class instead of the Thread class from Python's threading module.

    A simple example which uses QThread, signals and slots can be found on the PyQt Wiki:

    https://wiki.python.org/moin/PyQt/Threading,_Signals_and_Slots

    0 讨论(0)
  • 2020-12-12 20:22

    If your method "processDoc" doesn't change any other data (just looks for some data and return it and don't change variables or properties of parent class) you may use Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macroses ( see here for details ) in it. So the document will be processed in thread which will not lock the interpreter and UI will be updated.

    0 讨论(0)
  • 2020-12-12 20:34

    Native python queues won't work because you have to block on queue get(), which bungs up your UI.

    Qt essentially implements a queuing system on the inside for cross thread communication. Try this call from any thread to post a call to a slot.

    QtCore.QMetaObject.invokeMethod()

    It's clunky and is poorly documented, but it should do what you want even from from a non-Qt thread.

    You can also use event machinery for this. See QApplication (or QCoreApplication) for a method named something like "post".

    Edit: Here's a more complete example...

    I created my own class based on QWidget. It has a slot that accepts a string; I define it like this:

    @QtCore.pyqtSlot(str)
    def add_text(self, text):
       ...
    

    Later, I create an instance of this widget in the main GUI thread. From the main GUI thread or any other thread (knock on wood) I can call:

    QtCore.QMetaObject.invokeMethod(mywidget, "add_text", QtCore.Q_ARG(str,"hello world"))
    

    Clunky, but it gets you there.

    Dan.

    0 讨论(0)
提交回复
热议问题