正如前面所说,要使用QThread开始一个线程,我们可以创建它的一个子类,然后覆盖其QThread.run()函数:
class Thread(QThread): def __init__(self): super(Thread,self).__init__() def run(self): pass #线程相关代码
然后我们这样新建一个新的线程
thread=Thread() thread.start()这个默认实现其实是简单地调用了QThread.exec()函数,而这个函数,按照我们前面所说的,其实是开始了一个事件循环
QRunnable是我们要介绍的第二个类。这是一个轻量级的抽象类,用于开始一个另外线程的任务。这种任务是运行过后就丢弃的。由于这个类是抽象类,我们需要继承QRunnable,然后重写其纯虚函数QRunnable.run():
class Task(QRunnable): def __init__(self): super(QRunnable,self).__init__() def run(self): pass #线程相关代码要真正执行一个QRunnable对象,我们需要使用QThreadPool类。顾名思义,这个类用于管理一个线程池。通过调用QThreadPool.start(runnable)函数,我们将一个QRunnable对象放入QThreadPool的执行队列。一旦有线程可用,线程池将会选择一个QRunnable对象,然后在那个线程开始执行。所有 PyQt 应用程序都有一个全局线程池,我们可以使用QThreadPool.globalInstance()获得这个全局线程池;与此同时,我们也可以自己创建私有的线程池,并进行手动管理。
task=Task() QThreadPool.globalInstance().start(task)需要注意的是,QRunnable不是一个QObject,因此也就没有内建的与其它组件交互的机制。为了与其它组件进行交互,你必须自己编写低级线程原语,例如使用 mutex 守护来获取结果等。
QtConcurrent是我们要介绍的最后一个对象。这是一个高级 API,构建于QThreadPool之上,用于处理大多数通用的并行计算模式:map、reduce 以及 filter。它还提供了QtConcurrent.run()函数,用于在另外的线程运行一个函数。注意,QtConcurrent是一个命名空间而不是一个类,因此其中的所有函数都是命名空间内的全局函数。
不同于QThread和QRunnable,QtConcurrent不要求我们使用低级同步原语:所有的QtConcurrent都返回一个QFuture对象。这个对象可以用来查询当前的运算状态(也就是任务的进度),可以用来暂停/回复/取消任务,当然也可以用来获得运算结果。注意,并不是所有的QFuture对象都支持暂停或取消的操作。比如,由QtConcurrent.run()返回的QFuture对象不能取消,但是由QtConcurrent.mappedReduced()返回的是可以的。QFutureWatcher类则用来监视QFuture的进度,我们可以用信号槽与QFutureWatcher进行交互(注意,QFuture也没有继承QObject)。
下面我们可以对比一下上面介绍过的三种类:
特性 | QThread
|
QRunnable
|
QtConcurrent
|
高级 API | ✘ | ✘ | ✔ |
面向任务 | ✘ | ✔ | ✔ |
内建对暂停/恢复/取消的支持 | ✘ | ✘ | ✔ |
具有优先级 | ✔ | ✘ | ✘ |
可运行事件循环 | ✔ | ✘ | ✘ |