如何保持GUI的响应流畅(QT平台)

 

引子

  一般来说耗时较长的操作,分为计算密集型操作和IO密集型操作,对于这两类操作如何提高响应速度呢?

  而从操作的本质上来说,操作又可分为不可分解操作,如在第三方库中耗时较长的操作,以及可分解操作,其中可分解操作又可细分为串行操作和可并行操作,如何针对这几类操作来提高响应速度呢?

  如何将异步的操作,如网络库中异步的读取数据方法,变成同步的操作?

  此外对于多线程,普遍的看法是可以提供程序的运行速度,其实不然,不正确地使用线程常常会使程序变慢,那么在QT中是否可以通过多线程以外的方法来提高响应速度呢?

  下文将一一解答这些问题。

  正文

  首先什么是对GUI的响应?答:GUI的响应就是系统对于GUI事件的处理速度。

  由于系统处理事件需要一定的时间,所以一般窗口系统都会提供一个事件队列来存储事件。如果把每个事件处理看成一个任务的话,那么事件处理就类似于操作系统对于任务按照优先级进行处理,使得每个任务的平均等待时间最小。那么就可以借鉴一下操作系统中的方法,比如:

  分级,让较长的任务延后执行。

  分时,对于较长的任务,让其执行一段时间后暂停,然后再执行。

  减少每个任务运行的耗时,当然这是最基本的方法。

  先看第一个分级,当一个事件处理程序知道自己将执行耗时很长的操作时,可以调用QCoreApplication::processEvents() 方法,等待消息队列中的方法都执行完再执行。当然这是一个最基本的方法,只适用与简单的情况,如果事件队列中的另一程序也调用了该方法则会出现死锁。

  再看分时,它适用于可分解的操作(包括串行操作和并行操作),只需记录当前任务的执行情况,然后可以再次执行。它的使用流程如下:

  1: Function EventHandler()

  2: {

  3:     //开始计时

  4:     While(执行时间 < 用户可接受的响应时间)

  5:     {

  6:         //执行操作

  7:     }

  8:     //注册系统空闲事件以继续处理

  9: }

  在QT中注册系统空闲事件的方法可以通过QTimer::singleShot(0, this, SLOT(calculate()));将系统空闲信号注册到自己的槽中。或者使用QMetaObject::invokeMethod(this, "calculate", Qt::QueuedConnection);方法,通过invokeMethod异步的执行某个方法。

  最后重点看一下如何减少响应的时间,对于数据密集型操作,推荐使用ThreadPool来管理,减少线程上下文切换的时间;而对于IO密集型操作,则自己管理一个thread来实现,而这也是我认为thread最应该使用的情景,即让CPU和外设都处于满负荷运转状态,减少总的操作时间。

  对于并行操作响应时间的减少,在QT中引入了Qt Concurrent的概念,采用Map/Reduce的方式,具体可以参考QT中的Concurrent Programming节。

  最后再解答下如何在QT中将异步操作改成同步操作的方法,这个就属于QT special的内容,一般的读者可以跳过。

  具体的代码如下所示:

  1: QNetworkAccessManager manager;

  2: QEventLoop q;

  3: QTimer tT;

  4:

  5: tT.setSingleShot(true);

  6: connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));

  7: connect(&manager, SIGNAL(finished(QNetworkReply*)),

  8:         &q, SLOT(quit()));

  9: QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://www.qtcentre.org")));

  10:

  11: tT.start(5000); // 5s timeout

  12: q.exec();

  13:

  14: if(tT.isActive()){

  15:     // download complete

  16:     tT.stop();

  17: } else {

  18:     // timeout

  19: }

  其中主要利用了QEventLoop类,它将创建一个本地的Event loop,然后block,直到接受到finished信号,或者timeout超时信号后才退出,而事件循环则不会被block。

  总结

  本文分析了影响GUI响应速度的原因,通过类比操作系统对任务的优先级分派方式,探讨了对多种事件类型,提高其响应速度的方法,其中有些方法在其它平台也是通用的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值