异步模式的实现

什么是异步

异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回.实现异步可以采用多线程技术或则交给另外的进程来处理

 

异步的优缺点


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;
}

 

 

参考博客: https://www.cnblogs.com/qicosmos/p/3534211.html

posted @ 2020-08-12 20:14  知道了呀~  阅读(974)  评论(0编辑  收藏  举报