目录
什么是异步?
异步编程是一种编程范式,允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞或等待这些操作完成。
- 在传统的同步编程中,代码是按顺序执行的,每个操作必须等待前一个操作完成。这种方式在处理I/O操作、网络请求或计算密集型任务时可能会导致程序的性能瓶颈。例如,当程序需要从网络上获取数据时,它会等待数据返回后再继续执行,这期间CPU可能会处于空闲状态,浪费了资源。
- 异步编程则不同,它允许程序在等待操作完成的同时继续执行其他任务。例如,程序可以发起一个网络请求,然后继续执行其他操作,而不必等待网络请求完成。等到网络请求完成时,程序再处理返回的数据。
异步编程的优点
- 提高性能:通过并发执行多个任务,异步编程可以更高效地利用CPU资源。
- 提高响应速度:异步编程可以使程序在等待某些操作完成时继续响应用户输入,提高用户体验。
- 简化I/O操作:异步编程特别适合处理I/O密集型操作,如文件读取,网络请求等。
async和future的使用
什么是async
std::async:是一个函数模板,用于启动一个异步任务。它接受一个可调用的对象(如函数、Lambda表达式、函数对象等)作为参数,并在一个单独的线程上异步执行该对象。std:async自动管理异步任务的生命周期,并返回一个std::future对象,该对象可用于获取异步操作的结果。
什么是future
std::future:是一个模板类,用于表示异步操作的结果。它允许开发者在将来的某个时刻查询异步操作的状
态、等待操作完成或获取操作的结果。通常,std::future对象不是直接创建的,而是与std::async、 std::packaged_task或std::promise配合使用。
future的主要成员函数

代码示例
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int myfun(int a,int b)
{
cout << "this is myfun" << endl;
return a + b;
}
int main()
{
future<int> myf = async(myfun, 20, 30);
cout << "myf = " << myf.get() << endl;
return 0;
}
三种启动策略
future<int> myf = async(launch::async,myfun, 20, 30);
future<int> myf = async(launch::deferred, myfun, 20, 30);
future<int> myf = async(launch::async | launch::deferred, myfun, 20, 30);
第一种:launch::async
- 行为:该策略指示std::async必须异步地执行任务,即必须在一个新的线程中启动任务。这意味着调用std::async后,任务将立即在新线程中开始执行,而调用线程可以继续执行其他任务。
- 适用场景:当你需要确保任务在单独的线程中执行,并且不希望它阻塞当前线程时,应使用此策略。
第二种:launch::deferred
- 行为:该策略指示stdasync可以延迟任务的执行,直到调用std::future::get()或std:future::wait()方法时,任务才在当前线程中执行。如果任务从未被查询(即没有调用get()或wait()),则任务可能永远不会执行。
- 适用场景:当你希望仅在需要结果时才执行任务,或者当任务执行不会阻塞其他重要操作时,此策略可能很有用。然而,需要注意的是,使用此策略可能会隐藏潜在的并发问题,因为任务可能在查询结果时才执行。
第三种:launch::async | launch::deferred(默认策略)
- 行为:这个策略是std::launch::async和std::launch::deferred的组合,但它并不保证具体的执行方式。实际执行方式取决于实现(如编译器和库)以及系统资源。在某些情况下,任务可能会异步执行;在其他情况下,它可能会被延迟执行。
- 适用场景:由于此策略的行为是不确定的,因此它可能不适用于需要精确控制任务执行方式的场景。然而,作为默认策略,它提供了一种灵活的方式来启动异步任务,同时允许实现根据当前系统状况进行优化。
异步编程promise的用法
promise就是类似于一个篮子,用来获取异步的结果。
std::promise是一个用于设置异步操作结果的机制。它允许你在一个线程中设置值或异常,然后在另一个线程中通过std::future对象检索这些值或异常。std::promise通常与std::async、std::packaged_task或 std::thread结合使用,以在异步操作中传递结果。
一个Promise对象是为了保存某个特定的结果值分配的,这个结果值是在未来的某个时间点计算得到的。结果值可以是任意类型的值(void类型除外);也可以是指向常量和非常量(对象指针、函数或者成员函数)的指针;甚至是引用类型的“实值”。
一个Promise对象可以创建一个或多个std::future对象,用来承载该Promise对象所保存的结果值。只有当 set_value()或者set_exception()被调用,这些结果值才能被执行。一旦被执行,这些结果值就可以通过 std::future::get函数添加到std::future对象中。
执行过程
一个线程A生成线程B,在生成线程B的同时生成了一个篮子,把篮子传给了B线程,B拿到篮子之后开始执行结果,把执行结果通过set_value(RS)放进了篮子里,A线程通过future获得放进篮子的结果RS。

定义promise
你可以通过包含<future>头文件来使用std::promise。然后,你可以创建一个std::promise的实例,并指定它将要持有的值的类型。
promise<int> prom;
成员函数

示例代码
#include <iostream>
#include <future>
using namespace std;
void async_task(promise<int> prom)
{
this_thread::sleep_for(std::chrono::seconds(1));
prom.set_value(42);//设置异步操作的结果
}
int main()
{
promise<int> prom; //创建篮子
future<int> fut = prom.get_future(); //获取与promise 关联的future
thread t(async_task, move(prom));//启动异步任务,并将promise传递给它
cout << "The result is " << fut.get() << endl;
t.join();
return 0;
}
异步编程packaged_task
packaged_task是一个模板类,主要用于将一个可调用对象(如函数、lambda表达式、函数对象等)包装起来,以便异步地执行,并能够获取其返回结果。它和std::future以及std::thread紧密相关,经常用于多线程编程中。
注意:c++17才出现
使用流程
- 创建packaged_task:
在创建packaged_task对象时,你需要传递一个可调用对象(如函数、lambda表达式等)给它。这个对象会被封装在 packaged_task中,成为一个异步任务。 - 获取std::future:
使用get_future()方法可以获取与packaged_task关联的std::future对象,后者可以用于获取异步任务的结果。 - 执行任务:
任务可以通过operator()或者在一个新线程中调用std::thread 来执行。注意,这里的packaged_task对象必须通过std::move传递,因为 packaged_task不允许复制。 - 获取结果:
通过调用std::future的get()方法,调用线程可以等待异步任务完成并获取其返回值。如果任务尚未完成,get)将阻塞直到结果可用。

2130

被折叠的 条评论
为什么被折叠?



