首页 > 编程语言 >async++库的使用示例

async++库的使用示例

时间:2025-01-23 21:29:35浏览次数:3  
标签:std task cout 示例 demo c++ asyn 任务 async

1、普通异步函数

如前面的博客介绍的,这个库中提供了async::spawn方法,这个方法通常用来启动异步函数,这个框架会利用线程池去完成函数,因此要注意数据安全。正因为将任务放到了单独的线程执行,并且还有调度开销,因此简单的任务最好不要使用这种方法,得不偿失。示例代码如下:

void demo_async1() {
   std::mutex mutex;
   auto task1 = async::spawn(
       [&mutex]{
       {
	      std::lock_guard<std::mutex> lock(mutex); 
        std::cout << "this is in async thread" << std::endl;
	     }
	     return "hello world!!!"; 
	 }); 
	 while(!task1.ready()) {
	   std::lock_guard<std::mutex> lock(mutex);
	   std::cout << "this is in main thread" << std::endl;
	 }
   task1.wait();
   // 这里会获取任务的返回值,即"hello world!!!"
   auto ret = task1.get();
   std::cout << ret << std::endl;
};

2、带有子任务的普通异步函数

async::spawn函数返回的仍然是一个任务,因此可以连续使用then来执行子任务,示例代码如下:

void demo_async2() {
  async::spawn([] {
     return "hello world";
  }).then([](const std::string& s) {
     return s;
  }).then([](async::task<std::string> task) {
     std::cout << task.get() << std::endl;
  });
}

有没有发现第一个子任务所执行的函数参数是std::string,而第二个子任务所执行的函数参数是async::taskstd::string task,而前面两个任务返回的都是字符串。这是因为异步编程中的 .then() 方法和 async::task 类型的处理方式有些特殊。在链式调用中,.then() 并不仅仅是一个普通的函数调用,它是用来接收一个异步任务完成后的结果,并且会返回一个新的异步任务。这意味着第一个子任务返回的并不是字符串,返回的字符串会被封装成async::taskstd::string,所以第二个子函数的参数类型必须是 async::taskstd::string。而主任务的返回值是std::string,所以第一个子任务的函数参数可以是std::string。

3、when_any和when_all的使用

when_any是任务集合中有一个任务完成就会返回,when_all是多有的任务完成才会返回。需要注意的是,when_any并不是第一个任务完成了就不执行其他的任务,其它的任务仍在执行,只不过when_any不会等他们执行完再返回。这里在测试的时候,如果测试when_all,一定要先注释when_any,否则程序会崩溃,原因就是task和shared_task的原因。它们返回的包含结果的数据结构都是std::tuple类型的,想取得结果要么使用辅助函数,要么使用std::get<0>(results).get()这种。不能使用for遍历,因为tuple的各元素大小可能不一样。也不可以使用std::get<first_result.index>,原因很简单,模版函数需要再编译时确定值,而不可以在运行时确定。

void demo_async3() {
   // 定义三个异步任务,分别模拟不同的执行时间
   auto task1 = async::spawn([] {
	   std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟耗时任务
	   std::cout << "Task 1 completed!" << std::endl;
	   return 1;
   });
   auto task2 = async::spawn([] {
	   std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时任务
	   std::cout << "Task 2 completed!" << std::endl;
	   return 2;
   });
   auto task3 = async::spawn([] {
	   std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时任务
	   std::cout << "Task 3 completed!" << std::endl;
	   return 3;
   });
   //  // 使用 when_any 等待最早完成的任务
   //  auto any_result = async::when_any(task1, task2, task3);
   //  any_result.wait(); // 等待第一个任务完成
   //  auto first_result = any_result.get();
   //  std::cout << "First completed task returned: " << first_result.index << std::endl;
   
   // 使用 when_all 等待所有任务完成
   auto all_result = async::when_all(task1, task2, task3);
   all_result.wait(); // 等待所有任务完成
   auto results = all_result.get();
  // 因为是Tuple,静态容器,每个元素的大小可能不一样,所以可以用这种方式访问
  // 如果是C++1,可以使用std::apply()来遍历tuple
   std::cout << std::get<0>(results).get() << std::endl;
   std::cout << std::get<1>(results).get() << std::endl;
   std::cout << std::get<2>(results).get() << std::endl;
}

4、async::cancellation_token的使用

该异步框架提供了一个async::cancellation_token,它主要用来控制子任务的执行进度,是不是在主线程中取消子任务的执行,这样可以使得子线程中通过其控制子线程内部的执行进度,是不是取消(当然也可以做一些逻辑的控制)

void demo_async4() {
  async::cancellation_token c;
  auto t = async::spawn([&c] {  
  std::cout << "-----line 68" << std::endl;
  async::interruption_point(c);
  while(!c.is_canceled());
    std::cout << "-----line 70" << std::endl;
  });
  sleep(1);
  std::cout << "-----line 79" << std::endl;
  c.cancel();  
  t.get();
  std::cout << "-----line 82" << std::endl;
}

5、事件任务的使用

我认为时间任务的主要作用是在主线程中控制子任务的执行时间点,并可以像子任务重设置参数。

void demo_async5() {
  async::event_task<int> e;
  auto t = e.get_task();
  // 这里只是将后面的任务放到了e的continuation_vector
  t.then([](int result) { std::cout << result << std::endl; });
  // 执行主任务,并将参数传给子任务,触发子任务
  e.set(42);
}

6、共享任务的使用

共享任务的优点是可以多次获取任务的结果,不像普通的任务那样,获取完结果,就会把内存释放掉。缺点是使用了引用计数,增加了资源消耗,但是现代计算机中,这些资源的消耗造成的影响较小,这里的代码必须加share(),根因和task类shared_task类的定义有关系,task类不允许拷贝,但是允许移动构造,但是shared_task都是可以的,模仿的std::future和std::shared_future的关系。

// 从测试代码中可以看出,我们可以利用共享任务,将其以参数的形式传到其它任务中
void demo_async6() {
   // 使用 async::spawn 创建异步任务并使用 .share() 方法共享
    auto t = async::spawn([] {
        std::cout << "Parent task" << std::endl;
        return 42; // 返回一些结果
    }).share();
    
    // 创建两个任务,它们共享 t
    auto task1 = async::spawn([t] {
        auto result = t.get(); // 获取共享任务的结果
        std::cout << "Task 1 result: " << result << std::endl;
    });
    
    auto task2 = async::spawn([t] {
        auto result = t.get(); // 获取共享任务的结果
        std::cout << "Task 2 result: " << result << std::endl;
    });
    
    // 等待任务完成
    task1.get();
    task2.get();

7、测试程序

直接贴代码

#include <iostream>
#include <mutex>
#include <ctime>
#include <unistd.h>
#include "../include/async++.h"
/*
上面的示例
*/
int main() {
   // demo_async1();
   // demo_async2();
   demo_async3();
   // demo_async4();
   // 

标签:std,task,cout,示例,demo,c++,asyn,任务,async
From: https://blog.csdn.net/xiaoan08133192/article/details/145311448

相关文章

  • C++ 队列( queue )详解 加强版
    作者制作不易,关注、点赞、收藏一下吧!目录1.队列2.模拟队列2.1.入队(push)2.2.出队(pop)2.3.获取队首元素2.4.获取队尾元素2.5.获取队列长度2.6.判断队列是否为空3.直接使用队列(queue)3.1.普通队列3.1.1.入队(push)3.1.2.出队(pop)3.1.3.获取队首元素(......
  • 埃氏算法C++实现: 快速输出质数( 素数 )
    目录1.简介算法原理算法特点应用场景2.一般求素数方法3.埃氏算法求素数3.1.无动态分配3.2.有动态分配1.简介‌埃氏算法(EratosthenesSieve)‌,全称为埃拉托斯特尼筛法,是一种由古希腊数学家埃拉托斯特尼在公元前3世纪提出的古老而经典的算法,用于计算一定范围内的素数......
  • c++专题一
    C++框架&输入输出#include<iostream>usingnamespacestd;//写了这个之后使用标准库组件前面就不用写std::intmain(){​return0;}输入std::cin>>x输出std::cout<<"helloworld"<<std::endl;//std::endl用来换行格式化输出:#include<iomanip>//用于控制输出......
  • ACM 寒假第一讲:C++ 基础
    1.A-LongLoongProblemStatementForapositiveintegerX,theDragonStringoflevelXisastringoflength(X+3)formedbyoneL,Xoccurrencesofo,onen,andonegarrangedinthisorder.YouaregivenapositiveintegerN.PrinttheDragonStrin......
  • C++模板全解析:场景与注意点揭秘!
    C++作为现代编程语言中的一种,其强大功能和复杂性使得它在系统编程、应用开发等领域广受欢迎。其中,模板(Template)是C++语言中一个极为重要且强大的特性,它不仅提高了代码的复用性,还使得类型无关的编程成为可能。本文将详细介绍C++模板的基础知识,包括其概念、分类、常见应用场景及......
  • C++中static和const的区别和用法
    在C++中,static和const是两个关键字,它们各自有不同的用途和语法。下面是它们的主要区别和用法:const关键字const关键字用于声明一个常量,即该变量的值在初始化后不能被修改。用法:局部变量:voidfunc(){constinta=10;//a是一个常量,值为10,不能在函数内部修改......
  • 第一讲C++
    第一题LongLoongForapositiveintegerX,theDragonStringoflevelXisastringoflength(X+3)formedbyoneL,Xoccurrencesofo,onen,andonegarrangedinthisorder.YouaregivenapositiveintegerN.PrinttheDragonStringoflevelN.Noteth......
  • 国税发票查验-电子发票真伪查验API查验结果示例
    现如今,随着发票在业务场景中的广泛使用与电子发票的不断普及,企业面临的挑战之一是如何确保财务数据的高效与准确。在面对大量的财务发票时,通过传统手动录入与核对发票真伪的方法让财务工作者头疼不已,熬夜加班是财务的常态,且手动核验的方式极易出现人为误差,导致虚假发票进入......
  • c++迷宫问题(migong)
    今天的题目叫“迷宫问题(migong)”,是“DFS深度优先搜索递归”一类的。题目描述设有一个N*N(2<=N<10)方格的迷宫,入口和出口分别在左上角和右上角。迷宫格子中分别放0和1,0表示可通,1表示不能,入口和出口处肯定是0。迷宫走的规则如下所示:即从某点开始,有八个方向可走,前进方格中数......
  • c++瓷砖
    今天的题目叫“瓷砖”,是“DFS深度优先搜索递归”一类的。题目描述在一个w×h的矩形广场上,每一块1x1的地面都铺设了红色或黑色的瓷砖。小谢同学站在某一块黑色的瓷砖上,他可以从此处出发,移动到上、下、左、右四个相邻的且是黑色的瓷砖上。现在他想知道,通过重复上述移动所能......