C++11为异步操作提供了4个接口
- std::packaged_task:将可调用对象进行封装,使其能被异步or同步调用。
- std::aysnc: 异步or同步运行某个任务函数(std::aysnc≈std::thread+std::packaged_task)
- std::future : 异步指向某个任务,然后通过future特性去获取任务函数的返回结果。
- std::promise:承诺获取到值后,使其与之绑定的std::future处于就绪状态
如何理解他们的关系 std::packaged_task、std::aysnc、std::future 、std::promise
这里用一份外卖做类比:
- std::promise:外卖商家任务
- std::future:用户订购的外卖
- std::aysnc:外卖平台(黄袋鼠和小蓝帽),假设这里黄袋鼠是std::packaged_task,小蓝帽是std::thread,有两种不同的生产外卖模式
- 现在一个用户下单(std::aysnc)
- 则这时用户会预先得到一个未来的外卖(std::future)
- 平台则告知商家去做外卖并且给商家一个任务(std::promise)
- 当商家出餐后,把任务拍照告知给平台(std::promise::set_value(T))已经出餐
- 平台接收到商家承诺出餐完毕后,再把真实的外卖(std::future)送给用户
- 用户通过std::future::get()获取到最终的外卖产品
std::packaged_task与std::async的代码的差异
- std::packaged_task是将一个可调用对象(包括函数、函数对象、lambda表达式、std::bind表达式、std::function对象)进行包装,以便该任务能被异步调用
- std::async用于创建异步任务
相同点: 通过std::future对象返回执行结果 不同点: std::packaged_task需要等待执行结果返回,而std::async不必
代码释义
#include <functional>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
using namespace std;
namespace {
int AddFunc(int a, int b, int sleep)
{
cout << "==========================================================" << endl;
cout << "function thread id=" << std::this_thread::get_id() << endl;
cout << __FUNCTION__ << " sleep begin " << std::this_thread::get_id() << endl;
this_thread::sleep_for(chrono::seconds(sleep));
cout << __FUNCTION__ << " sleep end " << std::this_thread::get_id() << endl;
auto ret = a + b;
cout << "thread id=" << std::this_thread::get_id() << " ret = " << ret << endl;
cout << "==========================================================" << endl;
return ret;
}
}
void TestPackagedTask()
{
std::packaged_task<int(int, int, int)> task(AddFunc);
auto f1 = task.get_future();
auto start = std::chrono::high_resolution_clock::now();
task(1, 2, 3);
auto stop = std::chrono::high_resolution_clock::now();
std::cout << "diff time " << std::chrono::duration<float>(stop - start).count() << endl;
std::cout << f1.get() << std::endl;
}
void TestAsync()
{
auto ret_future1 = std::async(std::launch::deferred, AddFunc, 1, 2, 3);
auto start = std::chrono::high_resolution_clock::now();
auto result = ret_future1.get();
auto stop = std::chrono::high_resolution_clock::now();
std::cout << "diff time " << std::chrono::duration<float>(stop - start).count() << endl;
std::cout << result << std::endl;
}
int main()
{
TestAsync();
TestPackagedTask();
return 0;
}
运行结果: 简单的说区别就是std::async调用future.get()时则会执行此异步任务,但std::packaged_task 必须先执行operator()此异步任务,再调用future.get()获取返回值
std::async能否替代std::thread及不同?
不能 劣势:
- std::async必须设置std::launch::async此Policy时,才是真的开启新的线程执行,默认的Policy则会根据不同系统的实现及CPU运行情况,来最终异步or同步执行,具有不确定性
- 宏观上看std::aysnc≈std::thread+std::packaged_task
优势:
- std::async增加了返回值std::future,和std::thread相比,在某些需要返回值场景时,更加的抽象,代码更加简洁
|