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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • c++11&14-多线程要点汇总

    在C++11以前,C++的多线程编程均需依赖系统或第三方接口实现,一定程度上影响了代码的移植性.C++11中,引入了boost库中的多线程部分内容,形成C++标准,形成标准后的boost多线程编程部分接口基本没有变化,这样方便了以前使用boost接口开发的使用者切换使用C++标准接口,很容易把boost接口升级为C++标准接口. 我们通过如下几部分介绍C++11多线程方面的接口及使用方法. 1. std::thread std::thread为C++11的线程类,使用方法和boost接口一样,非

  • C++11 并发指南之多线程初探

    C++11 自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些 C++11 的新特性,今后几篇博客我都会写一些关于 C++11 的特性,算是记录一下自己学到的东西吧,和大家共勉. 相信 Linux 程序员都用过 Pthread, 但有了 C++11 的 std::thread 以后,你可以在语言层面编写多线程程序了,直接的好处就是多线程程序的可移植性得到了很大的提高,所以作为一名 C++ 程序员,熟悉 C++11 的多线程编程方式还是很有益处的. 如果你对 C++11

  • c++11新特性多线程操作实战

    c++11多线程操作 线程 thread int main() { thread t1(Test1); t1.join(); thread t2(Test2); t2.join(); thread t3 = t1; thread t4(t1); thread t5 = std::move(t1); thread t6(std::move(t1)); return 0; } t3,t4创建失败,因为thread的拷贝构造和赋值运算符重载的原型是: thread(const thread&) = d

  • C++11中std::async的使用详解

    C++11中的std::async是个模板函数.std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对象.Fn返回的值可通过std::future对象的get成员函数获取.一旦完成Fn的执行,共享状态将包含Fn返回的值并ready. std::async有两个版本: 1.无需显示指定启动策略,自动选择,因此启动策略是不确定的,可能是std::launch::async,也可能是std::launch

  • C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语言层面的thread可以解决这个问题. 所需头文件<thread> 二:构造函数 1.默认构造函数 thread() noexcept 一个空的std::thread执行对象 2.初始化构造函数 template<class Fn, class... Args> explicit th

  • 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

  • Python多线程编程之threading模块详解

    一.介绍 线程是什么?线程有啥用?线程和进程的区别是什么? 线程是操作系统能够进行运算调度的最小单位.被包含在进程中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 二.Python如何创建线程 2.1 方法一: 创建Thread对象 步骤: 1.目标函数 2.实例化Thread对象 3.调用start()方法 import threading # 目标函数1 def fun1(num): for i in range(

  • python 编程之twisted详解及简单实例

    python 编程之twisted详解 前言: 我不擅长写socket代码.一是用c写起来比较麻烦,二是自己平时也没有这方面的需求.等到自己真正想了解的时候,才发现自己在这方面确实有需要改进的地方.最近由于项目的原因需要写一些Python代码,才发现在python下面开发socket是一件多么爽的事情. 对于大多数socket来说,用户其实只要关注三个事件就可以了.这分别是创建.删除.和收发数据.python中的twisted库正好可以帮助我们完成这么一个目标,实用起来也不麻烦.下面的代码来自t

  • java多线程编程之Synchronized关键字详解

    本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章  一.分析 synchronized可以修饰实例方法,如下形式: public class MyObject { synchronized public void methodA() { //do something.... } 这里,synchronized 关键字锁住的是当前对象.这也是称为对象锁的原因. 为啥锁住当

  • java多线程编程之java线程简介

    一.线程概述 线程是程序运行的基本执行单元.当操作系统(不包括单线程的操作系统,如微软早期的DOS)在执行一个程序时,会在系统中建立一个进程,而在这个进程中,必须至少建立一个线程(这个线程被称为主线程)来作为这个程序运行的入口点.因此,在操作系统中运行的任何程序都至少有一个主线程.进程和线程是现代操作系统中两个必不可少的运行模型.在操作系统中可以有多个进程,这些进程包括系统进程(由操作系统内部建立的进程)和用户进程(由用户程序建立的进程):一个进程中可以有一个或多个线程.进程和进程之间不共享内存

  • java多线程编程之Synchronized块同步方法

    文章分享了4个例子对synchronized的详细解释 1.是否加synchronized关键字的不同 public class ThreadTest { public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); Thread t2 = new Thread1(example); t1.start(); t2.start(); } } cl

  • Java多线程编程之Lock用法实例

    锁是控制多个线程对共享资源进行访问的工具.通常,锁提供了对共享资源的独占访问.一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁.不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock(维护了一对相关的锁,一个用于只读操作,另一个用于写入操作) 的读写锁. 1.Lock提供了无条件的.可轮询的.定时的.可中断的锁获取操作,所有加锁和解锁的方法都是显式的. public interface Lock{ void lock(); //加锁 //优先考虑响应中断,而不是响应

  • Java多线程编程之CountDownLatch同步工具使用实例

    好像倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当到达0时,所有等待者就开始执行. java.util.concurrent.CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.用给定的计数初始化CountDownLatch.由于调用了countDown()方法,所以在当前计数到达零之前,await方法会一直受阻塞.之后,会释放所有等待的线程,await的所有后续调用都将立即返回.这种现

  • Java多线程编程之ThreadLocal线程范围内的共享变量

    模拟ThreadLocal类实现:线程范围内的共享变量,每个线程只能访问他自己的,不能访问别的线程. package com.ljq.test.thread; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * 线程范围内的共享变量 * * 三个模块共享数据,主线程模块和AB模块 * * @author Administrator * */ public class ThreadScopeS

  • java多线程编程之join方法的使用示例

    在上面的例子中多次使用到了Thread类的join方法.我想大家可能已经猜出来join方法的功能是什么了.对,join方法的功能就是使异步执行的线程变成同步执行.也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法.如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完.而使用join方法后,直到这个线程退出,程序才会往下执行.下面的代码演示了join的用法.

随机推荐