zoukankan      html  css  js  c++  java
  • 异步模式的实现

    什么是异步

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

    异步的优缺点


    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

  • 相关阅读:
    Android-PullToRefresh 下拉刷新增加setOnItemLongClickListener
    【453】周志华-机器学习-读书笔记
    【452】pandas筛选出表中满足另一个表所有条件的数据
    【451】python 同一行打印进度条
    【449】Win10 蓝牙耳机链接没有声音
    HBase(一)HBase入门简介
    kafka可视化客户端工具(Kafka Tool)的基本使用
    Kafka(五)Kafka的API操作和拦截器
    Kafka(四)Kafka在zookeeper中的存储
    Kafka(三)Kafka的高可用与生产消费过程解析
  • 原文地址:https://www.cnblogs.com/-citywall123/p/13490343.html
Copyright © 2011-2022 走看看