异步模式的实现
什么是异步
异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回.实现异步可以采用多线程技术或则交给另外的进程来处理
异步的优缺点
1、在设计良好的情况下,可以不是使用或减少共享变量的使用,减少了死锁的可能
2、编写异步操作的复杂度高,使用回调函数处理难以调试
异步与多线程
异步与多线程,从辩证关系上来看,异步和多线程并不时一个同等关系,异步是目的,多线程只是我们实现异步的一个手段(线程池).
硬件上实现异步
DMA就是直 接内存访问的意思,也就是说,拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源。只要CPU在发起数据传输时发送一个指令,
硬件就开 始自己和内存交换数据,在传输完成之后硬件会触发一个中断来通知操作完成。这些无须消耗CPU时间的I/O操作正是异步操作的硬件基础。
软件上实现异步
上面说了多线程是实现异步的一个手段、但是使用主函数调用异步处理线程的时候,比较难获取子线程的返回值(实际可以通过使用全局变量、指针、引用、promise+future),总体来说使用比较复杂,所以就有async()函数实现异步
std::async是更高层次上的异步操作,使我们不用关注线程创建内部细节,就能方便的获取异步执行状态和结果,还可以指定线程创建策略,应该用std::async替代线程的创建,让它成为我们做异步操作的首选。
async大概的工作过程是这样的:
1、furture声明未来的异步操作的结果
2、promise承诺这个结果的出现
3、packaged_task将异步任务包装起来,放到线程中执行(lambda 表达式)
4、最后通过wait()和wait_for()来获取异步任务的完成状态,根据这个状态选择调用get()来获取这个未来的结果
因为一个异步操作我们是不可能马上就获取操作结果的,只能在未来某个时候获取,但是我们可以以同步等待的方式来获取结果,可以通过查询future的状态(future_status)来获取异步操作的结果。
future_status是一个枚举的数据类型,有三种状态:
1、deferred:异步操作还没开始
2、ready:异步操作已经完成
3、timeout:异步操作超时
可以使用future的wait()、wait_for()、wait_untill()来获取任务的完成状态
1、wait()阻塞调用
2、wait()阻塞一个time_out时间
async异步调用函数的使用
async(launch,func,args)函数有三个参数,分别是启动方式、任务函数,参数列表
启动策略有三种方式
1、launch::deferred : 延迟调用异步函数,延迟到future对象调用get()或者wait()的时候才执行func();如果不调用get()或者wait(),func()不会执行。
2、launch::async :强制这个异步任务在一个新线程上执行,这意味着,系统必须要创建出一个新线程来运行func(),新线程创建失败抛出异常
3、launch::async| launch::deferred : 由系统自行决定选择那种启动方式
func的类型可以是函数指针、函数对象、lambda表达式
std::async与std::thread的区别
std::async()与std::thread()最明显的不同,就是async并不一定创建新的线程
std::thread() 如果系统资源紧张,那么可能创建线程失败,整个程序可能崩溃。
std::thread()创建线程的方式,如果线程返回值,你想拿到这个值也不容易;
std::async()创建异步任务,可能创建也可能不创建线程;并且async调用方式很容易拿到线程入口函数的返回值。
#include<iostream> #include<thread> #include<string> #include<vector> #include<list> #include<mutex> #include<future> using namespace std; int mythread() //线程入口函数 { cout << "mythread start " << "threadid= " << this_thread::get_id() << endl; //打印线程id chrono::milliseconds dura(5000); //定一个5秒的时间 this_thread::sleep_for(dura); //休息一定时常 cout << "mythread end " << "threadid= " << this_thread::get_id() << endl; //打印线程id return 5; } int main() { future<int> result = async(mythread);//默认方式启动线程、无参数传递 //获取异步任务的完成状态 //future_status是一个枚举类型的值,wait()和wait_for()返回该枚举类型的值 //wait()会阻塞调用线程,直到异步任务完成取消阻塞 //wait_for(time_out)会阻塞一段时间,在time_out时间内返回并结束阻塞 while (1) { future_status status = result.wait_for(std::chrono::seconds(1));//每一秒钟轮询一次状态 //异步操作还没被调用 if (status == future_status::deferred) { //调用开始 cout << result.get() << endl; } //异步操作超时 else if (status == future_status::timeout) { cout << "超时:表示线程还没执行完!" << endl; } //异步调用结束 else if (status == future_status::ready) { //表示线程成功返回 cout << "线程成功执行完毕,返回!" << endl; cout << result.get() << endl; break; } } cout << "Finish!" << endl; system("pause"); return 0; }