Taskflow:异步任务(Asynchronous Tasking)
简单使用
tf::Executor 提供了异步执行Task的操作tf::Executor::async,并返回Future,用于保留该函数调用的结果。
#include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl;
}int main() {tf::Executor executor;std::future<int> future = executor.async([](){print_str("async task");return 1;});print_str(std::to_string(future.get()).c_str());
}
如果不需要关系返回值,推荐使用Executor::silent_async ,相较于tf::Executor::async,减少了一些状态共享的开销:
#include <taskflow/taskflow.hpp>int main() {tf::Executor executor;executor.silent_async([](){print_str("async task");return 1;});// sleep 1sstd::this_thread::sleep_for(std::chrono::seconds(1));
}
调度器会自动检测异步任务是从外部线程还是工作线程提交的,并使用work stealing来安排其执行:
#include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl;
}
int main() {tf::Executor executor;tf::Taskflow taskflow;tf::Task my_task = taskflow.emplace([&executor](){// 从 my_task 内部启动一个异步任务executor.async([&executor](){// 从 一个异步任务内部启动一个异步任务,可能执行在其他worker线程中executor.async([&](){}); });});executor.run(taskflow);executor.wait_for_all(); // 等待所以任务执行结束
}
由分析工具,可以看到,这个嵌套的异步任务分别执行在不同的线程中:
从executor创建的异步任务不属于任何任务流。异步任务的生命周期由创建任务的executor自动管理。
Subflow 创建异步任务
Subflow也可以创建自己的异步任务,Taskflow保证这些异步任务在join前结束:
#include <cassert>
#include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl;
}
int main() {tf::Executor executor;tf::Taskflow taskflow;std::atomic<int> counter{0};taskflow.emplace([&executor,&counter](tf::Subflow& sbf){// 创建100个异步任务,注意,这里是Subflow创建的for(int i = 0; i < 100; i++) {sbf.silent_async([&counter](){++counter;});}// 显式调用join,这100个任务将会在这里全部完成sbf.join();assert(counter == 100); // 验证这里的所有异步任务均回收});executor.run(taskflow).wait();taskflow.dump(std::cout);
}
注意: 只可以在一个joinable 的Subflow中创建异步任务,从Detach的Subflow启动异步任务会导致未定义的行为。
为异步任务添加依赖(动态任务图)
动态任务图的优势:
- 探索任务图并行性:在一些应用场景中,任务之间的依赖关系可能不是事先完全确定的,而是会根据程序的运行状态动态变化。通过动态创建任务图,可以根据实时的控制流来调整任务的执行顺序和并行度,从而实现更高效的并行处理。
- 重叠任务图创建时间与任务执行时间:在传统的任务图构建方法中,通常需要先构建完整的任务图,然后再开始执行任务。但在某些情况下,我们可以在创建任务图的同时执行任务,这样可以减少等待任务图完全构建完成的时间,提高整体的执行效率。
创建一个动态任务图
当应用程序中无法构建任务图的运行模型时,可以使用tf::Executor::dependent_async和tf::Executor::silent_dependent_async来动态创建任务图。这种类型的并行性也被称为实时任务图并行性:
#include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl;
}
int main() {tf::Executor executor;// silent_dependent_async 返回一个AsyncTask对象,用于构建后续的任务依赖tf::AsyncTask A = executor.silent_dependent_async([&](){print_str("Task A");});// 构建任务依赖,B依赖Atf::AsyncTask B = executor.silent_dependent_async([&](){print_str("Task B");}, A);// 构建任务依赖,C依赖Atf::AsyncTask C = executor.silent_dependent_async([&](){print_str("Task C");}, A);// dependent_async 返回std::pair<tf::AsyncTask, std::future<void>>// D依赖B和C, fuD 来等待任务D执行完成auto [D, fuD] = executor.dependent_async([&](){print_str("Task D");}, B, C);fuD.get(); // 等待D执行完成
}
tf::Executor::dependent_async和tf::Executor::silent_dependent_async都创建一个类型为tf::AsyncTask的任务,以异步运行给定的函数。此外,tf::Executor::dependent_async返回一个std::future,最终保存执行结果。当从两个调用返回时,executor安排worker在满足其依赖项时运行任务。也就是说,任务执行与创建任务图同时进行,而不是如静态图一样,构建完整个图后再执行。
图左展示的是静态图的执行逻辑,先建图,再执行,而图右展示的是动态图的执行逻辑,边建图,边执行。
注意:动态图的构建只允许将当前任务的依赖项与之前创建的任务相关联,因此用户需要保证拓扑顺序的正确性。
另外,如果整个动态图均使用silent_dependent_async构建,也可以使用executor.wait_for_all()来保证所有异步任务均会完成。
int main() {tf::Executor executor;tf::AsyncTask A = executor.silent_dependent_async([](){ printf("A\n"); });tf::AsyncTask B = executor.silent_dependent_async([](){ printf("B\n"); }, A);tf::AsyncTask C = executor.silent_dependent_async([](){ printf("C\n"); }, A);tf::AsyncTask D = executor.silent_dependent_async([](){ printf("D\n"); }, B, C);executor.wait_for_all();
}
如果一个任务的依赖是依靠运行时的结果得出的,而不能显式指定,可以使用dependent_async和silent_dependent_async的重载,来动态确定:
#include <cstdio>
#include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl;
}
int main() {tf::Executor executor;std::vector<tf::AsyncTask> dependents; // 存放动态依赖int n = 0;printf("input n:");scanf("%d",&n); // 动态输入依赖数for(int i = 0; i < n; i++) {dependents.push_back(executor.silent_dependent_async([i](){char name[16];std::sprintf(name,"Task:%c\n", 'A'+i);print_str(name); })); // 创建异步任务,并添加到dependents中}executor.silent_dependent_async([](){print_str("All dependents completed\n");}, dependents.begin(), dependents.end()); // 创建异步任务,等待所有依赖完成executor.wait_for_all();
}
因为printf不是线程安全的,所以打印可能并不符合预期,但是执行顺序是正确的。
下图是n=8时的性能分析图:
可以看到,虽然依赖是运行时才确定的,但是任务的调度仍然保持着较高的并行度。
tf::AsyncTask是一个轻量级句柄,保留由executor创建的依赖异步任务的共享所有权。这种共享所有权确保异步任务在将其添加到另一个异步任务的依赖项列表中时保持活动状态,从而避免了经典的ABA问题。
// main thread retains shared ownership of async task A
tf::AsyncTask A = executor.silent_dependent_async([](){});// task A remains alive (i.e., at least one ref count by the main thread)
// when being added to the dependency list of async task B
tf::AsyncTask B = executor.silent_dependent_async([](){}, A);
注意: executor.silent_dependent_async和executor.dependent_async是线程安全的,即可以在多线程环境下安全地添加任务,只要拓扑上的任务在逻辑上是正确的。
同时,tf::AsyncTask也包含类似std::future一样的is_done方法,可重入future。
// create a dependent async task that returns 100
auto [task, fu] = executor.dependent_async([](){ return 100; });// loops until the dependent async task completes
while(!task.is_done());
assert(fu.get() == 100);
动态任务图计算斐波那契数列
有了动态任务图,就可以很方便地将一些递归任务拆解成并行任务:
#include <cstdio>
#include <taskflow/taskflow.hpp>
#include <tuple>void print_str(char const* str) {std::cout << str << std::endl;
}
int main() {tf::Executor executor;int n = 0;printf("input n:");scanf("%d",&n); // 动态输入依赖数std::function<int(int)> fibonacci; fibonacci = [&](int N){if(N < 2) {return N;}auto [t1, fu1] = executor.dependent_async(std::bind(fibonacci, N-1));auto [t2, fu2] = executor.dependent_async(std::bind(fibonacci, N-2));// worker内等待必须是corun_until,否则会死锁executor.corun_until([&](){ return t1.is_done() && t2.is_done(); });return fu1.get() + fu2.get();};auto [task, fib11] = executor.dependent_async(std::bind(fibonacci, n));std::cout<<"fibonacci("<<n<<") = "<<fib11.get()<<std::endl;
}
当n=5时,性能分析图如下:
相关文章:
Taskflow:异步任务(Asynchronous Tasking)
简单使用 tf::Executor 提供了异步执行Task的操作tf::Executor::async,并返回Future,用于保留该函数调用的结果。 #include <taskflow/taskflow.hpp>void print_str(char const* str) {std::cout << str << std::endl; }int main() …...
学习鸿蒙基础(9)
目录 一、鸿蒙国际化配置 二、鸿蒙常用组件介绍 三、鸿蒙像素单位介绍 四、鸿蒙布局介绍 1、Row与Column线性布局 2、层叠布局-Stack 3、弹性布局 4、栅格布局 5、网格布局 一、鸿蒙国际化配置 base目录下为默认的string。en_US对应美国的。zh_CN对应中国的。新增一个s…...
spring boot的小数位丢失.00 或者.0
1、背景 在使用spring boot时,前端的界面展示的数据是2 ,在数据库中存储的是小数。但是导出Excel的时候数据是 2.00 。奇了怪了为啥会不一样,数据都是一样的没有做过处理。 2、排查问题 经过层层的debug 发现数据库返回的数据是2.00&#x…...
nginx如何清理页面缓存
在 Nginx 中,清理页面缓存通常涉及配置缓存头以控制缓存行为,或者使用外部工具或机制来清除缓存。以下是一些建议来管理和清理 Nginx 的页面缓存: 配置缓存头: Nginx 本身不直接提供缓存机制,但可以通过配置 proxy_cac…...
深度学习pytorch——经典卷积网络之ResNet(持续更新)
错误率前五的神经网络(图-1): 图-1 可以很直观的看到,随着层数的增加Error也在逐渐降低,因此深度是非常重要的,但是学习更好的网络模型和堆叠层数一样简单吗?通过实现表明(图-2&…...
react 面试题(2024 最新版)
1. 对 React 的理解、特性 React 是靠数据驱动视图改变的一种框架,它的核心驱动方法就是用其提供的 setState 方法设置 state 中的数据从而驱动存放在内存中的虚拟 DOM 树的更新 更新方法就是通过 React 的 Diff 算法比较旧虚拟 DOM 树和新虚拟 DOM 树之间的 Chan…...
JVM(三)——字节码技术
三、字节码技术 1、类文件结构 一个简单的 HelloWorld.java package com.mysite.jvm.t5; // HelloWorld 示例 public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");} }执行 javac -parameters -d . HellowWorld.…...
HarmonyOS 应用开发之Stage模型绑定FA模型ServiceAbility
本小节介绍Stage模型的两种应用组件如何绑定FA模型ServiceAbility组件。 UIAbility关联访问ServiceAbility UIAbility关联访问ServiceAbility和UIAbility关联访问ServiceExtensionAbility的方式完全相同。 import common from ohos.app.ability.common; import hilog from o…...
高效解决Visual Studio无法识别到自定义头文件
文章目录 问题解决方案 问题 说明你没有好好配置项目属性 解决方案 把头文件都集中存放到一个文件夹里 之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路…...
[数据集][目标检测]道路行人车辆坑洞锥形桶检测数据集VOC+YOLO格式6275张4类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):6275 标注数量(xml文件个数):6275 标注数量(txt文件个数):6275 标注…...
风险与收益
风险与收益 影响资产需求的主要因素财富总量预期收益率资产的流动性影响流动性的主要因素 风险 如何降低风险系统风险和非系统风险机会集合与有效集合资产组合理论 影响资产需求的主要因素 影响资产需求的主要因素包括:财富总量、预期收益率、资产的流动性和风险。…...
linux服务器安装mysql8
1.下载MYSQL 近几天在linux服务器已安装过2次mysql8,亲测有效,没有遇到任何问题,文档已写的很清楚,按步骤来即可。如果按文档有遇到要使用yum命令的话,需要服务器开通外网。 1.1官网下载 进入官网下拉到最后&#x…...
亚信安全荣获2023年度5G创新应用评优活动两项大奖
近日,“关于2023 年度5G 创新应用评优活动评选结果”正式公布,亚信安全凭借在5G安全领域的深厚积累和创新实践,成功荣获“5G技术创新的优秀代表”和“5G应用创新的杰出实践”两项大奖。 面向异构安全能力的5G安全自动化响应系统 作为5G技术创…...
linux之忘记root密码
一,开机到如下地方按下e进入紧急模式 然后再如下位置输入init/bin/bash 然后Ctrlx 二, 修改密码 以上操作分别为 1),重新挂载根目录 mount -o remount,rw / 2),修改密码 passwd root 3)&a…...
jspm智能仓储系统
开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…...
深入理解数据结构(3):栈和队列详解
文章主题:顺序表和链表详解🌱所属专栏:深入理解数据结构📘作者简介:更新有关深入理解数据结构知识的博主一枚,记录分享自己对数据结构的深入解读。😄个人主页:[₽]的个人主页&#x…...
单例设计模式(3)
单例模式(3) 实现集群环境下的分布式单例类 如何理解单例模式中的唯一性? 单例模式创建的对象是进程唯一的。以springboot应用程序为例,他是一个进程,可能包含多个线程,单例代表在这个进程的某个类是唯一…...
将jupyter notebook文件导出为pdf(简单有效)
1.打开jupyter notebook笔记: 2.点击file->print Preview 3.在新打开的页面右键打印 4.另存为PDF 5.保存即可 6.pdf效果 (可能有少部分图片显示不了) 网上也有其他方法,比如将其转换为.tex再转为PDF等,但个人觉…...
使用INSERT INTO ... ON DUPLICATE KEY UPDATE批量插入更新导入excel数据的实践场景应用
INSERT INTO ... ON DUPLICATE KEY UPDATE 是 MySQL 中的一个非常有用的语法,它允许你在插入新记录时,如果记录的唯一键(如主键或唯一索引)已存在,则执行更新操作而不是插入。这可以帮助你避免在插入数据时产生的重复键…...
AJAX-项目优化(目录、基地址、token、请求拦截器)
目录管理 基地址存储 在utils/request.js配置axios请求基地址 作用:提取公共前缀地址,配置后axios请求时都会baseURLurl 填写API的公共前缀后,将js文件导入到html文件中 <script src"../../utils/request.js"></script&…...
SQLite中的动态内存分配(五)
返回:SQLite—系列文章目录 上一篇:SQLite中的原子提交(四) 下一篇:自己编译SQLite或将SQLite移植到新的操作系统(六) 概述 SQLite使用动态内存分配来获得 用于存储各种对象的内存 (例如…...
快速上手Spring Cloud 十一:微服务架构下的安全与权限管理
快速上手Spring Cloud 一:Spring Cloud 简介 快速上手Spring Cloud 二:核心组件解析 快速上手Spring Cloud 三:API网关深入探索与实战应用 快速上手Spring Cloud 四:微服务治理与安全 快速上手Spring Cloud 五:Spring …...
如何简化多个 if 的判断结构
多少算太多? 有些人认为数字就是一,你应该总是用至少一个三元运算符来代替任何单个 if 语句。我并不这样认为,但我想强调一些摆脱常见的 if/else 意大利面条代码的方法。 我相信很多开发人员很容易陷入 if/else 陷阱,不是因为其…...
发掘服务器硬件优势:怎样有效管理、维护、更新
1. 概述 服务器是许多信息技术的核心,通过提供计算和存储资源,以用于企业和机构的数据处理和存储。服务器硬件也是服务器的核心组成部分,在服务器架构和配置中扮演着重要角色。 服务器硬件的优势: - 提供更高的性能和处理能力。…...
SD卡备份和烧录ubuntu20.04镜像
设备及系统:nuc幻影峡谷工控机,ubuntu20.04,树莓派4B,SD卡读卡器 一、确定SD卡设备号的两种方法 方法1: 将有ubuntu镜像的SD卡插入读卡器,再将读卡器插入电脑主机,在 工具 中打开 磁盘&#…...
短视频账号矩阵系统/开发 -- -- -- 蒙太奇算法上线
短视频账号矩阵系统,短视频矩阵系统开发3年技术之路,目前已经在技术竞品出沉淀出来,近期技术迭代的新的功能同步喽: php7.4版本,自研框架,有开发文档,类laravel框架 近期剪辑迭代的技术算法&am…...
Docker Stack(堆栈) 部署多服务集群,多服务编排
1、Docker Stack简介 Docker Stack(堆栈) 是在 Swarm 上管理服务堆栈的工具。而在以前文章docker swarm集群搭建 介绍的 Docker Swarm 只能实现对单个服务的简单部署,于是就引出了Docker Stack。 上面我们介绍到 docker-compose:可以在一台机器上使用…...
全国青少年软件编程(Scratch)等级考试二级考试真题2023年12月——持续更新.....
青少年软件编程(图形化)等级考试试卷(二级) 分数:100 题数:37 一、单选题(共25题,共50分) 1.在制作推箱子游戏时,地图是用数字形式储存在电脑里的,下图是一个推箱子地图,地图表示如下: 第一行(111111) 第二行(132231) 第三行(126621) 第四行( ) 第五行(152…...
python基础——异常捕获【try-except、else、finally】
📝前言: 这篇文章主要介绍一下python基础中的异常处理: 1,异常 2,异常的捕获 3,finally语句 🎬个人简介:努力学习ing 📋个人专栏:C语言入门基础以及python入门…...
JAVA面试大全之JVM和调优篇
目录 1、类加载机制 1.1、类加载的生命周期? 1.2、类加载器的层次? 1.3、Class.forName()和ClassLoader.loadClass()区别?...
网站突然消失了/域名怎么注册
构造思路: 1.socket 连接获取 Banner --> 2.与存在漏洞的 Banner 集合进行对比 中间细节: 1.需要判断用户所给参数是否存在且是否有读权限 2.需要判断 Banner 是否存在,处理异常 学习 os sys socket 各个模块的基本使用 直接上代码&…...
深圳 b2c 网站建设/百度学术官网入口
一、AI可解释性 1.什么是可解释性? 可解释性,就是我们需要完成一件事的时候,我们能获取到的足够多的,能让我们自己理解的信息。当我们不能获得足够多的信息,来理解一件事情的时候,我们可以说这是不可解释…...
web技术的网站开发/服务推广软文
机械迷城手机免费版完整版下载手游是一款拥有十分独特的铅笔画风制作的冒险解密手机游戏。游戏讲述了一个需要不断对付各种黑帽黑帮的小机器的故事。这里的许多角色都是机器人设计的,所以你需要拯救你的女朋友。与此同时,你将不断地与更多的坏人打交道&a…...
做动画网站去哪采集/中国最厉害的营销策划公司
本文地址:http://www.cnblogs.com/archimedes/p/win-tc-graphics-use.html,转载请注明源地址。 由于最近接到一个紧急任务,需要实现一个程序,显示一些分形几何中的图形,例如:Koch曲线 感觉java的swing的界面…...
自己服务器建设网站/百度查询关键词排名工具
大家在利用镶嵌数据集管理影像的过程中,遭受过影像黑边的困扰吗?所谓的黑边就是在影像接边处有黑色的区域,严重影响视觉效果。 图 镶嵌数据集黑边示意 我们先来分析一下黑边产生原因:在使用镶嵌数据集管理影像数据的过程中&#…...
用vue做pc端网站好吗/线上营销活动案例
经常有人问到oracle中的Where子句的条件书写顺序是否对SQL性能有影响,我的直觉是没有影响,因为如果这个顺序有影响,Oracle应该早就能够做到自动优化,但一直没有关于这方面的确凿证据。在网上查到的文章,一般认为在RBO优…...