使用QFuture类监控异步计算的结果
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Amnes1a/article/details/65630701
在Qt中,为我们提供了好几种使用线程的方式,除了最基本的QThread类之外,还有QRunnable抽象类,类似于Java的runnable接口,还可以使用moveToThread() 函数,还有更高级的QtConcurrent框架。而今天,我们要看的QFuture就是和QtConcurrent框架API配合使用的一个类。新来看Qt帮助文档对这个类的详细介绍。
QFuture类用来表示一个异步计算的结果,而该异步计算通常就是由Qt Concurrent框架中的相关函数开启的。QFuture允许线程同步的获得一个或多个在将来某个时间点才准备好的结果。这些结果可以是任何具有默认构造函数和拷贝构造函数的类型。如果在调用该类的result()、resultAt() 或 results() 函数时,某个结果还不可用,QFuture会等待直到该结果可用,即可得到。当然,你也可以使用isResultReadyAt() 函数来判断某个结果是否已经准备好了。对于那些要获得多个结果的QFuture对象来说,resultCount() 函数会返回可以得到的连续结果的个数。这也意味着,我们在0和resultCount() 之间对QFuture对象进行遍历,总是安全的。并且,处理使用刚才说的下标外,QFuture还提供了Java类型的和STL类型的迭代器供我们使用。
使用QFuture对象,我们也可以和正在运行中的异步计算进行交互。例如,可以使用cancel() 函数取消一个异步计算;使用setPaused()、pause()、resume()、或者 togglePaused() 函数暂停一个异步计算。但要记住,并不是所有的异步计算都能被取消或暂停。例如,QtConcurrent()::run() 方法返回的future不能被取消,但是QtConcurrent::mappedReduced() 函数返回的future就可以。
除了刚才说的暂停操作,我们还可以获得异步计算的当前进度信息,progressValue()、progressMinimum()、progressMaximum()和progressText() 函数可以帮我们提供这些信息。
一个比较重要的函数就是waitForFinished(),该函数会导致调用线程阻塞来等待异步计算结束,以确保所有的结果都是可用的。
上面讲到,我们可以手工的暂停或取消一个异步计算,相对的,QFuture也为我们提供了查询当前计算状态的方法。比如,isCanceled(),isStarted(),isFinished(),isRunning()和 isPaused()函数。
QFuture是一个轻量级的引用计数类,所以它可以被当做参数值传递。
其实,在构建QFuture的对象时,我们会同时指定一个模板参数,表示QFuture要处理的结果的类型。其中,QFuture<void>是一个特化的不包含获取结果函数的QFuture对象。内可以将一个QFuture<void>对象赋值给一个QFuture<T>对象,反过来亦可。这对于那些只关注异步计算的状态或进度信息,而不关注实际结果的QFuture对象来说是及其有用的。
但这个类不支持信号和槽,若想使用信号和槽来和异步计算进行通信,需要使用QFutureWatcher类。
下面,我们再来看一下QFuture类中常用的一些函数。
QFuture::QFuture()
QFuture::QFuture(const QFuture &other)
QFuture::~QFuture()
构造函数到没什么好说的,一般使用第一个就好,构造一个QFuture对象,然后用该对象接收QtConcurrent::run() 或 QtConcurrent::mappedReduced()之类的函数的返回值即可。
但我们要记住,当QFuture对象析构时,既不会等待也不会取消异步计算。我们应该使用waitForFinished() 或者 QFutureSynchronizer类还确保在该对象析构之前所有的异步计算都完成。
void QFuture::cancel()
取消该对象代表的异步计算。但请注意,该取消动作也是异步的。如果想同步等待取消完成,要在调用cancel() 函数后,调用一下waitForFinished() 函数。
被取消的future对象,我们仍然可以从中提取到已经可用的结果,但是,在调用cancel() 之后,不会再有新的结果变的可用,而该future对象上的所有QFutureWatcher对象都不会在向我们传送进度信息和结果可用的信号。
再次重申,不是所有的异步计算都可以取消。参看上面已经说过的。
bool QFuture::isCanceled() const
判断异步计算是否被cancel() 函数取消了,但要注意,我们在上面讲cancel() 函数的时候就说过,cancel动作是异步,也就是说当这个函数返回true的时候,异步计算可能还在运行。
void QFuture::pause()
暂停当前future对象代表的异步计算。等价于setPaused(true)
bool QFuture::isPaused() const
判断一个异步计算是否被pause() 函数暂停了。同样,暂停动作也是异步的。
至于其他的成员方法,也都非常容易理解,见名知意,大家在使用时,具体参考Qt帮助文档即可。
上面我们说到,QFuture在取得异步结果方面除了提供了相关的result() 函数,还提供了方便的迭代器类,既有STL风格的QFuture::const_iterator,也有Java风格的QFutureIterator类。其中,STL风格的迭代器和STL中容器的迭代器一样,重载了*和->运算符,以及其他常用的++,--等运算符。而Java风格的迭代器则提供了hasNext()、next()等函数。下面我们分别来看看。
STL风格的迭代器,即QFuture::const_iterator,我们可以定义一个该类型的变量,然后使用QFuture::constBegin() 进行初始化。如下代码所示:
QFuture<QString> future = ...;
QFuture<QString>::const_iterator i;
for (i = future.constBegin(); i != future.constEnd(); ++i)
cout << *i << endl;
同样,对于Java风格的迭代器来说,由于其是一个c++类,所以其构造函数接受一个要进行迭代的QFuture对象,然后使用next() 函数进行逐个遍历。例如以下代码所示:
QFuture<QString> future;
...
QFutureIterator<QString> i(future);
while (i.hasNext())
qDebug() << i.next();
除了next()方法外,QFutureIterator类还提供了previous() 函数,可以完成从后想起的反向遍历。如下代码所示:
QFutureIterator<QString> i(future);
i.toBack();
while (i.hasPrevious())
qDebug() << i.previous();
下面,我们就来写一个使用QFuture的简单例子。因为我们还没讲到QtConcurrent框架及其API,所以,我们就简单的用一下QtConcurrent::run()方法,来启动一个函数,在此函数中计算第100个斐波那契数。代码如下:
#include <QCoreApplication>
#include <QFuture>
#include <QtConcurrent>
#include <QDebug>
//计算第lindex 个 斐波那契数值
qulonglong Fibonacci(int index)
{
qulonglong f1 = 1, f2 = 1, cur = 0;
for(int i = 3; i <= index; i++)
{
cur = f1 + f2;
f1 = f2;
f2 = cur;
}
return cur;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFuture<qulonglong> future = QtConcurrent::run(Fibonacci, 100);
//future.waitForFinished();
qDebug() << "test";
qDebug() << future.result();
return a.exec();
}
在此,我们通过使用run()方法,就启动了一个异步计算,紧接着我们调用result() 函数,取得该异步计算的结果。如果此时该结果还不可用,那么调用该函数会是函数阻塞等待结果。当然,我们也可以先调用waitForFinished() 等待其运行结束。其输出结果如下:
先打印出 “test” 字符串,可见,我们通过run() 启动的Fibonacci() 函数确实是异步执行的,并没有阻塞我们的main函数的执行流程。
另外,QtConcurrent在Qt中是一个独立的命名空间,所以还要在.pro文件中引入该模块。如下:
QT += core concurrent
至于QtConcurrent中的其他函数及其相关类,会在后续博文中讲解。
再上面的例子中,我们只是使用QtConcurrent::run()开启了一个异步计算,然后调用QFuture::result() 等待计算的结果。但其实同一时间,我们可以同时开启多个并行运行的异步计算,然后分别使用一个QFuture对象等待结果。但其实在Qt中,为了简化多个QFuture的同步等待操作,特地为我们提供了一个模板类QFutureSynchronizer。该类为我们提供了 addFuture()和setFuture()函数,我们可以使用这两个函数,将代表多个异步计算的QFuture对象添加到一个QFutureSynchronizer对象中,然后调用该类的waitForFinished()方法,该方法就是用来等待所有的QFuture结束。
简单使用例子如下:
void someFunction()
{
QFutureSynchronizer<void> synchronizer;
synchronizer.addFuture(QtConcurrent::run(anotherFunction));
synchronizer.addFuture(QtConcurrent::map(list, mapFunction));
return; // 等待所有的异步计算结束才返回
}
除了等待函数外,QFutureSynchronizer类还提供了一setCancelOnWait()方法,若通过这个函数设置了cancel-on-wait标志,那么调用waitForFinished()函数会取消所有未完成的计算。
下面,我们在上面求斐波那契数的例子中,再开启一个异步计算,同时求出两个斐波那契数
#include <QCoreApplication>
#include <QFuture>
#include <QFutureSynchronizer>
#include <QtConcurrent>
#include <QDebug>
//计算第lindex 个 斐波那契数值
qulonglong Fibonacci(int index)
{
qulonglong f1 = 1, f2 = 1, cur = 0;
for(int i = 3; i <= index; i++)
{
cur = f1 + f2;
f1 = f2;
f2 = cur;
}
return cur;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFutureSynchronizer<qulonglong> synchronizer;
synchronizer.addFuture(QtConcurrent::run(Fibonacci, 50));
synchronizer.addFuture(QtConcurrent::run(Fibonacci, 100));
synchronizer.waitForFinished();
qDebug() << "第50个斐波那契数: " << synchronizer.futures()[0].result();
qDebug() << "第100个斐波那契数: " << synchronizer.futures()[1].result();
return a.exec();
}
运行结果如下:
---------------------
作者:求道玉
来源:CSDN
原文:https://blog.csdn.net/Amnes1a/article/details/65630701
版权声明:本文为博主原创文章,转载请附上博文链接!
使用QFuture类监控异步计算的结果的更多相关文章
- java异步计算Future的使用(转)
从jdk1.5开始我们可以利用Future来跟踪异步计算的结果.在此之前主线程要想获得工作线程(异步计算线程)的结果是比较麻烦的事情,需要我们进行特殊的程序结构设计,比较繁琐而且容易出错.有了Futu ...
- Task:取消异步计算限制操作 & 捕获任务中的异常
Why:ThreadPool没有内建机制标记当前线程在什么时候完成,也没有机制在操作完成时获得返回值,因而推出了Task,更精确的管理异步线程. How:通过构造方法的参数TaskCreationOp ...
- Knockout v3.4.0 中文版教程-5-计算监控-使用计算监控
3. 计算监控 1.使用计算监控 如果你有一个监控的属性firstName和另一个lastName,但你想显示全名怎么办? 这就是引入计算监控的原因-这是依赖于一个或多个其他的observables函 ...
- C++类的大小计算汇总
C++中类涉及到虚函数成员.静态成员.虚继承.多继承.空类等. 类,作为一种类型定义,是没有大小可言的. 类的大小,指的是类的对象所占的大小.因此,用sizeof对一个类型名操作,得到的是具有该类型实 ...
- OpenACC 异步计算
▶ 按照书上的例子,使用 async 导语实现主机与设备端的异步计算 ● 代码,非异步的代码只要将其中的 async 以及第 29 行删除即可 #include <stdio.h> #in ...
- Math类的数学计算功能
//Math类的数学计算功能 public class MathTest { public static void main(String[] args) { /*----------下面是三角运算- ...
- 13.FutureTask异步计算
FutureTask 1.可取消的异步计算,FutureTask实现了Future的基本方法,提供了start.cancel 操作,可以查询计算是否完成,并且可以获取计算 的结果.结果 ...
- 怎样给ExecutorService异步计算设置超时
ExecutorService接口使用submit方法会返回一个Future<V>对象.Future表示异步计算的结果.它提供了检查计算是否完毕的方法,以等待计算的完毕,并获取计算的结果. ...
- gearman(异步计算)学习
Gearman是什么? 它是分布式的程序调用框架,可完成跨语言的相互调 用,适合在后台运行工作任务.最初是2005年perl版本,2008年发布C/C++版本.目前大部分源码都是(Gearmand服务 ...
随机推荐
- Redis 配置文件及命令详解
==基本配置 daemonize no 是否以后台进程启动 databases 16 创建database的数量(默认选中的是database 0) save 900 1 #刷新快照到硬盘中,必须满足 ...
- php中的可变变量、可变函数、匿名函数
1.可变变量 简而言之:获取一个普通变量的值作为这个可变变量的变量名. 如: $a = "hello"; $$a = " world"; /* $a 的值为&q ...
- js知识地图--js大脑图beta01版正式发布
原文地址 http://zhangyaochun.iteye.com/blog/1682605 原作者:zhangyaochun
- nginx.conf 详细
##定义nginx运行的用户各用户组user nginx nginx; ##nginx进程数,建议设置与cpu核心数一致worker_processes 1; ##全局错误日志定义类型[ debug ...
- 集成学习1-Boosting
转自http://blog.csdn.net/lvhao92/article/details/51079018 集成学习大致分为两类,一类串行生成.如Boosting.一类为并行化.如Bagging和 ...
- Xcode中授权普通成员
问题: 在普通用户账户下使用系统的Xcode在编译通过时候会提示” Developer Tools Access“需控制另一进程,需要输入“Developer Tools”组用户名密码才能继续调试 解 ...
- Struts2 主题和模板
实际本章教程开始之前,让我们看看由http://struts.apache.org给出的几个定义: Term 描述 tag A small piece of code executed from wi ...
- Spring 入门之-dao使用jdbcTemplate(注入过程)
技巧:在为把dataSourc连接池注入到jdbcTemplate里面时,学到一招:按住CTRL 不松,点击相关类名,可以自动跳转或打开. 说明:主要过程, 1.创建UserDao和UserServi ...
- Android Otto框架浅析
今天要介绍的是一个Android中使用得比較多的android 事件总线 EventBus模式的一个框架Otto. Otto 官网:http://square.github.io/otto/ 一.An ...
- android自定义View_0——Create a custom view class
一:创建一个自定义view的原则: 1.符合android的标准 2.能在layout的xml中定义控件属性 3.实现些新功能 4.要兼容android的大多数版本 二:定义一个view的子类 1.可 ...