PyQt has many options for obtaining asynchronous behavior. For things that require event handling (e.g. QtNetwork, etc.), you should use the QThread example, which I presented in my other answer to this thread. But for the vast majority of your flow needs, I think this solution is far superior to other methods.
The advantage of this is that QThreadPool schedules your QRunnable instances as tasks. This is similar to the task pattern used in Intel TBB. It is not as elegant as I like, but it is great for asynchronous behavior.
This allows you to use most of the Qt streaming power in Python using QRunnable and still use signals and slots. I use the same code in several applications, some of which are hundreds of asynchronous REST calls, some of which open files or directory directories, and the best part uses this method, the Qt task balances system resources for me.
import time from PyQt4 import QtCore from PyQt4 import QtGui from PyQt4.QtCore import Qt def async(method, args, uid, readycb, errorcb=None): """ Asynchronously runs a task :param func method: the method to run in a thread :param object uid: a unique identifier for this task (used for verification) :param slot updatecb: the callback when data is receieved cb(uid, data) :param slot errorcb: the callback when there is an error cb(uid, errmsg) The uid option is useful when the calling code makes multiple async calls and the callbacks need some context about what was sent to the async method. For example, if you use this method to thread a long running database call and the user decides they want to cancel it and start a different one, the first one may complete before you have a chance to cancel the task. In that case, the "readycb" will be called with the cancelled task data. The uid can be used to differentiate those two calls (ie. using the sql query). :returns: Request instance """ request = Request(method, args, uid, readycb, errorcb) QtCore.QThreadPool.globalInstance().start(request) return request class Request(QtCore.QRunnable): """ A Qt object that represents an asynchronous task :param func method: the method to call :param list args: list of arguments to pass to method :param object uid: a unique identifier (used for verification) :param slot readycb: the callback used when data is receieved :param slot errorcb: the callback used when there is an error The uid param is sent to your error and update callbacks as the first argument. It there to verify the data you're returning After created it should be used by invoking: .. code-block:: python task = Request(...) QtCore.QThreadPool.globalInstance().start(task) """ INSTANCES = [] FINISHED = [] def __init__(self, method, args, uid, readycb, errorcb=None): super(Request, self).__init__() self.setAutoDelete(True) self.cancelled = False self.method = method self.args = args self.uid = uid self.dataReady = readycb self.dataError = errorcb Request.INSTANCES.append(self) # release all of the finished tasks Request.FINISHED = [] def run(self): """ Method automatically called by Qt when the runnable is ready to run. This will run in a separate thread. """ # this allows us to "cancel" queued tasks if needed, should be done # on shutdown to prevent the app from hanging if self.cancelled: self.cleanup() return # runs in a separate thread, for proper async signal/slot behavior # the object that emits the signals must be created in this thread. # Its not possible to run grabber.moveToThread(QThread.currentThread()) # so to get this QObject to properly exhibit asynchronous # signal and slot behavior it needs to live in the thread that # we're running in, creating the object from within this thread
When you exit the application, you want you to cancel all tasks or the application freezes before the completion of each scheduled task.
Matthew Levine Dec 16 '15 at 2:03 2015-12-16 02:03
source share