c++11多线程编程之std::async的介绍与实例

 更新时间:2020年11月02日 10:51:37   作者:小麒麟666  
这篇文章主要给大家介绍了关于c++11多线程编程之std::async的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

本节讨论下在C++11中怎样使用std::async来执行异步task。

C++11中引入了std::async

什么是std::async

std::async()是一个接受回调(函数或函数对象)作为参数的函数模板,并有可能异步执行它们.

template<class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);

std::async返回一个 std::future<T>,它存储由 std::async()执行的函数对象返回的值。

函数期望的参数可以作为函数指针参数后面的参数传递给std::async()。

std::async中的第一个参数是启动策略,它控制std::async的异步行为,我们可以用三种不同的启动策略来创建std::async

·std::launch::async

保证异步行为,即传递函数将在单独的线程中执行

·std::launch::deferred

当其他线程调用get()来访问共享状态时,将调用非异步行为

·std::launch::async | std::launch::deferred

默认行为。有了这个启动策略,它可以异步运行或不运行,这取决于系统的负载,但我们无法控制它。

如果我们不指定一个启动策略,其行为将类似于std::launch::async | std::launch::deferred

本节我们将使用std::launch::async启动策略

我们可以在std::async传递任何回调,如:

·函数指针

·函数对象

·lambda表达式

std::async的需求

假设我们必须从数据库和文件系统里里获取一些数据(字符串),然后需要合并字符串并打印。

在单线程中,我们这样做:

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
 
using namespace std::chrono;
 
std::string fetchDataFromDB(std::string recvData) {
 //确保函数要5秒才能执行完成
 std::this_thread::sleep_for(seconds(5));
 
 //处理创建数据库连接、获取数据等事情
 return "DB_" + recvData;
}
 
std::string fetchDataFromFile(std::string recvData) {
 //确保函数要5秒才能执行完成
 std::this_thread::sleep_for(seconds(5));
 
 //处理获取文件数据
 return "File_" + recvData;
}
 
int main() {
 //获取开始时间
 system_clock::time_point start = system_clock::now();
 
 //从数据库获取数据
 std::string dbData = fetchDataFromDB("Data");
 
 //从文件获取数据
 std::string fileData = fetchDataFromFile("Data");
 
 //获取结束时间
 auto end = system_clock::now();
 
 auto diff = duration_cast<std::chrono::seconds>(end - start).count();
 std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
 
 //组装数据
 std::string data = dbData + " :: " + fileData;
 
 //输出组装的数据
 std::cout << "Data = " << data << std::endl;
 
 return 0;
}

输出:

Total Time Taken  = 10 Seconds
Data = DB_Data :: File_Data

由于函数  fetchDataFromDB() 和  fetchDataFromFile()各自在单独的线程中运行5秒,所以,总共耗时10秒。

既然从数据库和文件系统中获取数据是独立的并且都要耗时,那我们可以并行地运行他们。

一种方式是创建一个新的线程传递一个promise作为线程函数的参数,并在调用线程中从关联的std::future对象获取数据

另一种方式就是使用std::async

使用函数指针调用std::async作为回调

修改上面的代码,并使用std::async异步调用fetchDataFromDB()

std::future<std::string>resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
 
std::string dbData = resultDromDB.get()

std::async()做如下的事情

·自动创建一个线程(或从内部线程池中挑选)和一个promise对象。

·然后将std::promise对象传递给线程函数,并返回相关的std::future对象

·当我们传递参数的函数退出时,它的值将被设置在这个promise对象中,所以最终的返回值将在std::future对象中可用

现在改变上面的例子,使用std::async异步地从数据库中获取数据

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
 
using namespace std::chrono;
 
std::string fetchDataFromDB(std::string recvData) {
 //确保函数要5秒才能执行完成
 std::this_thread::sleep_for(seconds(5));
 
 //处理创建数据库连接、获取数据等事情
 return "DB_" + recvData;
}
 
std::string fetchDataFromFile(std::string recvData) {
 //确保函数要5秒才能执行完成
 std::this_thread::sleep_for(seconds(5));
 
 //处理获取文件数据
 return "File_" + recvData;
}
 
int main() {
 //获取开始时间
 system_clock::time_point start = system_clock::now();
 
 std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
 
 //从文件获取数据
 std::string fileData = fetchDataFromFile("Data");
 
 //从DB获取数据
 //数据在future<std::string>对象中可获取之前,将一直阻塞
 std::string dbData = resultFromDB.get();
 
 //获取结束时间
 auto end = system_clock::now();
 
 auto diff = duration_cast<std::chrono::seconds>(end - start).count();
 std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
 
 //组装数据
 std::string data = dbData + " :: " + fileData;
 
 //输出组装的数据
 std::cout << "Data = " << data << std::endl;
 
 return 0;
}

输出:

Total Time taken= 5Seconds
Data = DB_Data :: File_Data

只使用了5秒

用Function对象作为回调调用std::async

/*
* Function Object
*/
struct DataFetcher {
 std::string operator ()(std::string recvdData) {
  //确保函数要5秒才能执行完成
  std::this_thread::sleep_for(seconds(5));
  //处理获取文件数据
  return "File_" + recvdData;
 
 }
};
 
//用函数对象调用std::async
std::future<std::string> fileResult = std::async(DataFetcher(), "Data"); 

用lambda函数作为回调调用std::async

std::future<std::string> resultFromDB = std::async([](std::string recvdData) {
 
 std::this_thread::sleep_for(seconds(5));
 //处理创建数据库连接、获取数据等事情
 return "DB_" + recvdData;
 
}, "Data"); 

总结

到此这篇关于c++11多线程编程之std::async的文章就介绍到这了,更多相关c++11多线程编程std::async内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C++ 拷贝构造函数

    详解C++ 拷贝构造函数

    这篇文章主要介绍了C++ 拷贝构造函数的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Eclipse中C++连接mysql数据库

    Eclipse中C++连接mysql数据库

    这篇文章主要为大家详细介绍了Eclipse中C++连接mysql数据库 ,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • C语言基础之二分查找知识最全汇总

    C语言基础之二分查找知识最全汇总

    这篇文章主要介绍了C语言基础之二分查找知识最全汇总,文中有非常详细的二分查找基础知识详解,对正在学习C语言基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • C 语言中实现环形缓冲区

    C 语言中实现环形缓冲区

    本文主要是介绍 C语言实现环形缓冲区,并附有详细实现代码,具有一定的参考价值,希望能帮助有需要的小伙伴
    2016-07-07
  • C语言递归在实践题目中应用详解

    C语言递归在实践题目中应用详解

    递归是C语言中非常重要的知识点,其中的大事化小等思想对初学C语言的小伙伴来说不是很友好,因此我整理了递归的经典题目并向外拓展,给你全面的介绍,重新认识递归
    2022-05-05
  • C++超详细讲解内存空间分配与this指针

    C++超详细讲解内存空间分配与this指针

    this 指针在C++类和对象中是个很方便实用的关键字,可以简化对象成员属性的调用,使代码表达的含义更加准确;在之前的学习中我们都可以判断变量所占内存空间大小,那么我们创建的类对象所占的内存空间怎么计算呢?想知道this的妙用和类对象占用的内存空间就来跟我学习吧
    2022-05-05
  • 浅析C++中static的一些用法

    浅析C++中static的一些用法

    static是静止的,静态的意思,那它有什么用呢,今天通过实例代码讲解下C++中static的一些用法,感兴趣的朋友跟随小编一起看看吧
    2022-12-12
  • 利用Matlab制作环形相册效果详解

    利用Matlab制作环形相册效果详解

    这篇文章主要为大家介绍了如何利用Matlab制作出环形相册的效果,文中的示例代码讲解详细,对我们学习Matlab有一定帮助,需要的可以参考一下
    2022-03-03
  • QT自定义QTextEdit实现大数据的实时刷新显示功能实例

    QT自定义QTextEdit实现大数据的实时刷新显示功能实例

    TextEdit是我们常用的Qt控件,用来显示文本信息,下面这篇文章主要给大家介绍了关于QT自定义QTextEdit实现大数据的实时刷新显示功能的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • QT的QWebEngineView类知识点详细介绍

    QT的QWebEngineView类知识点详细介绍

    QWebEngineView是Qt框架中的组件,基于Chromium内核,支持HTML5、CSS3、JavaScript等Web技术,适用于嵌入网页内容到Qt应用程序,它提供了丰富的接口如加载、导航、与JavaScript交互等,并支持信号槽机制处理各种网页事件,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-10-10

最新评论