C++并发 高级接口:async()和Future的使用方法

本文详细介绍了C++中async()和Future的使用,阐述了如何利用它们实现并行处理,以减少整体运行时间。通过示例展示了如何启动并行任务,如何获取和处理结果,以及异步调用的发射策略和异常处理。同时,强调了正确处理参数和避免并发问题的重要性。
摘要由CSDN通过智能技术生成

async()

是一个函数模板,提供一个接口,用来启动一个异步任务,移动成功的话返回一个future对象,也就是让一个可调用的对象若是可能的话在后台运行,成为一个独立线程。

Class future<>

允许你等待线程结束并获取其结果,可以通过调用其成员函数get()来获取结果.future提供了一种访问异步操作结果的机制,也就是说这个结果你可能无法马上得到,但不久的将来在线程执行完毕的时候,你就能够拿到结果。也就是future的意思。

asyncFuture的第一个用例

假设我们需要计算两个操作数的总和,这两个操作数是两个函数 的返回值,寻常做法如下:

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();
int result = func2() + result1.get();中, result1.get();可能在func2()之前被调用,于是你又一次获得了循序式处理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值