C++11异步编程 ---- std::async与std::future的使用和注意事项

介绍
异步与同步编程

在我们编程的过程中,经常会听到这样的名词,这里就对同步和异步作一个简单的解释:

  • 同步编程:同步编程,即是一种典型的请求-响应模型,当请求调用一个函数或方法后,需等待其响应返回,然后执行后续代码。

    一般情况下,同步编程,代码按序依次执行,能很好的保证程序的执行,但是在某些场景下,比如读取文件内容,或请求服务器接口数据,需要根据返回的数据内容执行后续操作,读取文件和请求接口直到数据返回这一过程是需要时间的,网络越差,耗费时间越长。
    如果使用同步编程,那么在等待返回结果的过程中,程序将阻塞在这里,如果是界面程序,无法刷新界面导致无响应,那将是致命的。因此,这里就需要使用异步编程了。

  • 异步编程:异步编程就是让耗时的函数异步执行,而不阻塞当前的线程。但我们想要获取执行结果怎么办,那我们通常需要使用回调函数来完成,使用回调却并不是那么好处理,因为是异步的,回调函数就必须知道关键的上下文才能知道这个结果要怎么使用,这也是异步编程的一大难点。

注意:异步和多线程是有区别的,异步并不一定就是多线程,如消息队列,将要执行的任务添加到消息队列,然后并不是在添加任务时执行,而是等轮到它了才执行,它们可以在同一线程,这也是一种异步。
    因此C++11提供的异步编程高级封装就显得格外的好用,std::async返回的std::future就用来获取其执行结果,十分方便。

std::async与std::future
std::async
  • std::async是C++11才有的一个异步调用模板,它将异步地运行传入的函数并返回一个std::future。合理地使用,可以更轻松地完成异步操作。
  • std::async是与std::future搭配使用的,但我们一般不直接使用std::future,而是使用对其封装的std::async,基本上可以代替std::thread完成所有任务。
  • std::async实际上是封装了std::promise,std::packaged_task,std::thread和std::future,然后提供给我们的一个异步编程的高级封装,让我们无需考虑太多的细节。
std::future

std::future提供了访问异步操作结果的机制,让我们在异步操作中能方便安全的获取异步操作的结果。
详细介绍可见C++11之std::future对象使用说明

使用示例
简单使用
  • auto future = std::async(f,args):在没给出执行策略(policy)的情况下,f的执行取决于实现,即有可能是在新线程中执行,也有可能在调用future.get()后在调用线程执行。因此最好是在使用时给出执行策略。
示例1-1
#include <iostream>
#include <future>
void print(int n) {
   
   for (int i = 0; i < n; i++) {
   
     std::cout << ".";
     std::this_thread::sleep_for(std::chrono::milliseconds(1000));
   }
   std::cout << std::endl;
}
int main(){
   
	auto future = std::async(print, 5);
	future.get(); // 这句可以不写,可见注意事项第一点
	return 0; // 结果:.....
}
示例1-2

std::future有如下函数:
在这里插入图片描述
此处测试使用wait_for
在这里插入图片描述

示例2:1-n分部求和

举个简单的栗子,来说明async的用处之一:分部求和,当一个函数可以拆成几部分互不影响的执行时,就可以让其多个线程来异步处理,以加快处理速度。

  • 普通的求和函数:
    int64_t Sum(int64_t from, int64_t to) {
         
        int64_t ret = 0;
        for (; from <= to; ++from) {
         
          ret += from;
        }
        return ret;
     }
    
  • 分部求和的函数:
    int64_t Sum_with_MultiThread(int64_t from, int64_t to, size_t thread_num) {
         
        int64_t ret = 0;
        int64_t n = thread_num ? (to - from) / thread_num : (to - from);
        std::vector<std::future<int64_t>> v;
        for (; from <= to; ++from) {
         
          v.push_back(std::async(Sum, from, from + n > to ? to : from + n));
          from += n;
        }
        for (auto &f : v) {
         
          ret += f.get();
        }
        return ret;
     }
    

让我们写出测试代码:

#include <iostream>
#include <future>
int main(){
   
	std::cout << Sum(1, 1000000000) << std::endl;
    std::cout << Sum_with_MultiThread(1, 1000000000, 4) << std::endl; // 最多4线程,因为cpu只有4核
    // TestTimeUsed是我写的测试用时的函数,后面给出
    std::cout << Tools::TestTimeUsed(Sum_with_MultiThread, 1, 1000000000, 4) << std::endl; // 最多4线程,因为cpu只有4核
    std::cout << Tools::TestTimeUsed(Sum, 1, 1000000000) << std::endl;
	return 0;
}

运行结果:可以看出4个线程计算差不多就是四分之一的时间。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值