async()
是一个函数模板,提供一个接口,用来启动一个异步任务,移动成功的话返回一个future对象,也就是让一个可调用的对象若是可能的话在后台运行,成为一个独立线程。
Class future<>
允许你等待线程结束并获取其结果,可以通过调用其成员函数get()来获取结果.future提供了一种访问异步操作结果的机制,也就是说这个结果你可能无法马上得到,但不久的将来在线程执行完毕的时候,你就能够拿到结果。也就是future的意思。
async
和Future
的第一个用例
假设我们需要计算两个操作数的总和,这两个操作数是两个函数 的返回值,寻常做法如下:
func1()+func2();
这意味着对操作数的处理是循序发生的。程序首先调用func1()在调用func2().或是颠倒过来。但是,无论怎么样,整体处理时间是func1()加上func2()所花时间,再加上计算综合所花的时间.
但是我们可以尝试并行运行func1()和func2(),使其整体运行时间只需是func1()和func2()运行时间中的较大者,加上计算总和的时间
下面是例子:
#include <chrono>
#include <future>
#include <thread>
#include <random>
#include <iostream>
using namespace std;
int doSomething(char c)
{
default_random_engine dre(c);
uniform_int_distribution<int>t(10, 1000);
for (int i = 0; i < 10; i++)
{
this_thread::sleep_for(chrono::microseconds(t(dre)));
cout.put(c).flush();
}
return c;
}
int func1()
{
return doSomething('.');
}
int func2()
{
return doSomething('+');
}
int main()
{
cout << "starting func1() in background and func2() in foreground: " << endl;
future<int>result1(async(func1));
int result2 = func2();
int result = result1.get() + result2;
cout << "\nresult of func1()+ func2(): " << result << endl;
}
future<int>result1(async(func1));
int result2 = func2();
int result = result1.get() + result2;
在上面代码中,我们首先使用async尝试启动func1()于后台,并将结果赋值给某个future对象:
future<int>result1(async(func1));
在这里async()尝试将其所获得的函数立即异步启动于一个分离线程内。因此概念上func1()在这里被启动了,不会造成main()停滞.基于两个原因,返回future对象是必要的:
1.它允许你取得传给aync的那个函数的未来结果-也许是个返回值,也许是个异常.这个future 对象已受到被启动函数返回类型的特化,如果被启动的是个返回无物的后台任务,这就会是future<void>
2.它必须存在,确保目标函数或快或慢终会被调用.注意之前说,async()尝试启动目标函数,如果没有启动,我们需要这个future 对象来强迫启动.因此,即使你对启动于后台的那个函数结果不感兴趣,还是需要有这个future对象
…
…
接下来我们启动了func2()于前台,这是个正常的同步化调用,程序在此停滞:
int result2 = func2();
如果先前func1()成功地被async()启动且尚未结束。现在func1()和func2()就是并行运行.
接下来处理总和,为了获得func1(),我们需要对先前返回的future object调用get():
int result = result1.get() + result2;
随着get被调用,以下三件事情一定会发生:
1.如果func1()被async()启动于一个分离线程中并且已结束,你会立即获得结果
2.如果func1()被启动但尚未结束,get()会引发停滞等待func1()结束后获得结果
3.如果func1()尚未启动,会被强迫启动如同一个同步调用;get()会引发停滞直至结果产生
这样的行为非常重要,原因如下:如果当async()无法启动新线程时,程序仍能正常运作
注意
:
调用async()并不一定保证传入的函数一定会被启动和结束.如果有线程处于可用状态,那么它的确会启动,但如果不是这样,这一调用会被推迟至你明确说你需要结果(也就是调用get())或只是希望目标函数完成任务(也就是调用wait())
也就是可能会有两种结果,一种结果如下:
另一种结果情况是这样的:
总结:
让程序更迅速的一般性做法是:修改程序使它受益于并行处理,但仍能够在单线程环境中正确运作。为了达到这个目标,你必须要这样做:
1.#include<future>
2.传递某些可并行执行的函数,交给std::async()
作为一个可调用对象
3.将执行结果赋值给一个future<ReturnType>object
4.当你需要那个被启动函数的执行结果,或当你想确保该函数结束,就对future<>object
调用get()
5.如果没有调用get()就不保证func1()一定会被调用.如果async()无法立即启动它收到的函数,就会推迟调用,使得当程序调用get()才被调用。如果没有这种明确请求,即使main()终止造成程序结束,也不会唤醒后台线程.
此外,还需要注意:
你必须确保只在最必要时才请求被async()启动的那个函数的执行结果。比如以下例子,可能不是你想要的:
future<int>result1(async(func1));
int result = func2() + result1.get();