Taskflow:条件任务(Conditional Tasking)

基本使用

条件任务评估一组指令,并返回要执行的下一个后续任务的整数索引。
该索引是根据其继任者结构的顺序定义的,首先,创建一个最简单的if else条件模块:

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    auto [init, cond, yes, no] = taskflow.emplace(
        [](){ std::cout << "init\n"; },
        [](){ return std::rand()%2; }, // 返回后继者的索引
        [](){ std::cout << "yes\n"; },
        [](){ std::cout << "no\n"; }
    );

    cond.succeed(init).precede(yes, no);
    executor.run(taskflow).wait();
    taskflow.dump(std::cout);
}

在这里插入图片描述

注意: 对于cond节点后继的索引正确性,需要依靠用户来保证,如果cond返回的索引超过了合法区间,这个executor将不会调度任务任务。

当然,稍加修改节点的依赖,就可以实现循环逻辑:

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    auto [init, cond, stop] = taskflow.emplace(
        [](){ std::cout << "init\n"; },
        [](){ std::cout << "flipping a coin\n"; return std::rand()%2; }, // 返回后继者的索引
        [](){ std::cout << "stop\n"; }
    );

    // 循环结构, cond 在 init 之后,在cond,stop之前
    cond.succeed(init).precede(cond, stop);
    executor.run(taskflow).wait();
    taskflow.dump(std::cout);
}

在这里插入图片描述

这种设计方式可以通过简单的代码实现相当复杂的任务逻辑:

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;


    tf::Task A = taskflow.emplace([](){}).name("A");
    tf::Task B = taskflow.emplace([](){}).name("B");
    tf::Task C = taskflow.emplace([](){}).name("C");
    tf::Task D = taskflow.emplace([](){}).name("D");
    tf::Task E = taskflow.emplace([](){}).name("E");
    tf::Task F = taskflow.emplace([](){}).name("F");
    tf::Task G = taskflow.emplace([](){}).name("G");
    tf::Task H = taskflow.emplace([](){}).name("H");
    tf::Task I = taskflow.emplace([](){}).name("I");
    tf::Task K = taskflow.emplace([](){}).name("K");
    tf::Task L = taskflow.emplace([](){}).name("L");
    tf::Task M = taskflow.emplace([](){}).name("M");
    tf::Task cond_1 = taskflow.emplace([](){ return std::rand()%2; }).name("cond_1");
    tf::Task cond_2 = taskflow.emplace([](){ return std::rand()%2; }).name("cond_2");
    tf::Task cond_3 = taskflow.emplace([](){ return std::rand()%2; }).name("cond_3");

    A.precede(B, F);
    B.precede(C);
    C.precede(D);
    D.precede(cond_1);
    E.precede(K);
    F.precede(cond_2);
    H.precede(I);
    I.precede(cond_3);
    L.precede(M);

    cond_1.precede(B, E);       // return 0 to 'B' or 1 to 'E'
    cond_2.precede(G, H);       // return 0 to 'G' or 1 to 'H'
    cond_3.precede(cond_3, L);  // return 0 to 'cond_3' or 1 to 'L'
    taskflow.dump(std::cout);
}

在这里插入图片描述

常见流程图设计准则

为了了解执行者如何安排条件任务,定义了两种依赖类型,强依赖和弱依赖。强大的依赖性是从非条件任务到另一个任务的前一个环节。弱依赖项是从条件任务到另一个任务的前一个链接。任务的从属数量是强依赖和弱依赖的总和。

  1. 单无源节点,减少竞争
  2. 无源节点不是条件节点
  3. 一个节点最好不要混合依赖(既有强依赖,又有弱依赖/条件依赖)

在这里插入图片描述

实现控制流图

if else 型

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    int i;
    // create three condition tasks for nested control flow
    auto initi = taskflow.emplace([&](){ i=3; }); 
    auto cond1 = taskflow.emplace([&](){ return i>1 ? 1 : 0; }); 
    auto cond2 = taskflow.emplace([&](){ return i>2 ? 1 : 0; }); 
    auto cond3 = taskflow.emplace([&](){ return i>3 ? 1 : 0; }); 
    auto equl1 = taskflow.emplace([&](){ std::cout << "i=1\n"; }); 
    auto equl2 = taskflow.emplace([&](){ std::cout << "i=2\n"; }); 
    auto equl3 = taskflow.emplace([&](){ std::cout << "i=3\n"; }); 
    auto grtr3 = taskflow.emplace([&](){ std::cout << "i>3\n"; }); 

    initi.precede(cond1);
    cond1.precede(equl1, cond2);  // goes to cond2 if i>1
    cond2.precede(equl2, cond3);  // goes to cond3 if i>2
    cond3.precede(equl3, grtr3);  // goes to grtr3 if i>3
    taskflow.dump(std::cout);
}

在这里插入图片描述

switch 型

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    auto [source, swcond, case1, case2, case3, target] = taskflow.emplace(
        [](){ std::cout << "source\n"; },
        [](){ std::cout << "switch\n"; return rand()%3; },
        [](){ std::cout << "case 1\n"; return 0; },
        [](){ std::cout << "case 2\n"; return 0; },
        [](){ std::cout << "case 3\n"; return 0; },
        [](){ std::cout << "target\n"; }
    );

    source.precede(swcond);
    swcond.precede(case1, case2, case3);
    target.succeed(case1, case2, case3);
    taskflow.dump(std::cout);
}

在这里插入图片描述

注意: 在switch型中,case节点必须是条件节点(也就是说必须要有返回值),因为如果是普通的静态节点,那么taget节点强依赖于case1、case2、case3 三个节点,但是这三个节点只会有一个被执行,这就导致targer永远无法完成前置依赖,导致永久等待。

实现do while 循环式

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    int i;

    auto [init, body, cond, done] = taskflow.emplace(
    [&](){ std::cout << "i=0\n"; i=0; },
    [&](){ std::cout << "i++ => i="; i++; },
    [&](){ std::cout << i << '\n'; return i<5 ? 0 : 1; },
    [&](){ std::cout << "done\n"; }
    );  

    init.precede(body);
    body.precede(cond);
    cond.precede(body, done);
    taskflow.dump(std::cout);
}

在这里插入图片描述

while Loop 型

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    int i;

    auto [init, cond, body, back, done] = taskflow.emplace(
    [&](){ std::cout << "i=0\n"; i=0; },
    [&](){ std::cout << "while i<5\n"; return i < 5 ? 0 : 1; },
    [&](){ std::cout << "i++=" << i++ << '\n'; },
    [&](){ std::cout << "back\n"; return 0; },
    [&](){ std::cout << "done\n"; }
    );

    init.precede(cond);
    cond.precede(body, done);
    body.precede(back);
    back.precede(cond);
    taskflow.dump(std::cout);
}

在这里插入图片描述
注意这里的细节,i++节点后,不能立马指向 while < 5 的条件节点,因为i++ 是普通节点,对cond做强制依赖,会导致死锁,如下图所示:

在这里插入图片描述
在上面的任务流程图中,调度器从init开始,然后减少循环条件任务的强依赖性,而i<5。在此之后,仍然存在一个强大的依赖性,即由循环主体任务i++引入。然而,在循环条件任务返回0之前,任务i++不会被执行,导致死锁

多条件任务

多条件任务是条件任务的广义版本。在某些情况下,应用程序需要从父任务跳转到多个分支。这可以通过创建一个多条件任务来完成,该任务允许任务选择一个或多个后续任务来执行。与条件任务类似,多条件任务返回一个整数索引向量,该向量指示多条件任务完成后要执行的继任者。该指数是根据多条件任务之前的继任者顺序定义的。

#include <taskflow/taskflow.hpp>

int main() {
    tf::Taskflow taskflow;
    tf::Executor executor;

    auto A = taskflow.emplace([]() -> tf::SmallVector<int> {
        std::cout << "A\n"; 
        return {0, 2}; // 表示0 和 2 都可以激活
    }).name("A");

    auto B = taskflow.emplace([&](){ std::cout << "B\n"; }).name("B");
    auto C = taskflow.emplace([&](){ std::cout << "C\n"; }).name("C");
    auto D = taskflow.emplace([&](){ std::cout << "D\n"; }).name("D");
    A.precede(B, C, D);
    executor.run(taskflow).wait();   
    taskflow.dump(std::cout);
}

在这里插入图片描述
在这里,B和D均消除了前置依赖,所以都会往下执行。同样,后继索引的正确性,需要由用户自己保证,对于错误的索引,Taskflow会直接略过。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/502972.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

暴力破解pdf文档密码

首先安装pdfcrack工具包 apt install pdfcrack 默认密码字典存储在/usr/share/wordlists里&#xff0c;是gz文件&#xff0c;将它解压并copy到pdf目录 然后使用pdfcrack破解 密码在最后一行user-password的单引号里

计算机网络——31数据链路层和局域网引论和服务

数据链路层和局域网 WAN&#xff1a;网络形式采用点到点链路 带宽大&#xff0c;距离远&#xff08;延迟大&#xff09; 贷款延迟积大 如果采用多点连接方式 竞争方式&#xff1a;一旦冲突代价大令牌等协调方式&#xff1a;在其中协调节点的发送代价大 点到点链路的链路层服…

基于SpringBoot和Vue的教学管理系统的设计与实现

今天要和大家聊的是一款基于SpringBoot和Vue的教学管理系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&#x1f…

理解游戏服务器架构-逻辑底层架构

目录 前言 什么是逻辑底层架构 逻辑底层架构的职责 1&#xff09;Thread-线程 线程管理 线程通讯 线程安全锁机制 2&#xff09;Network-网络 网络模型 网络消息协议 断线重连 网络安全 防范重复消息 防范篡改消息内容 防范篡改内存数据 网络承载 3&#xff0…

使用nvm管理nodejs版本

文章目录 1、下载NVM2、选择NVM安装3 、查询版本号&常用命令4、nvm命令安装指定版本node4.1 安装指定node4.2 查看是否安装成功4.3 切换node版本到你想要的版本4.4 再次查看nvm版本列表4.5 nvm其他常用命令 这个是每个全能前端经常会用到的&#xff0c;之前用过现在重装了&…

基于SSM的戒烟网站(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的戒烟网站&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMv…

新能源汽车充电桩常见类型及充电桩站场的智能监管方案

随着新能源汽车市场的迅猛发展&#xff0c;充电桩作为支持其运行的基础设施&#xff0c;也呈现出多样化的类型。这些充电桩不仅在外形和功能上存在差异&#xff0c;更在充电速度、充电方式以及使用场景等方面展现出独特的优势。 一、充电桩类型及区别 1、慢充桩&#xff08;交…

Android 12系统源码_多窗口模式(一)和多窗口模式相关方法的调用顺序

前言 从 Android 7.0 开始&#xff0c;Google 推出了一个名为“多窗口模式”的新功能&#xff0c;允许在设备屏幕上同时显示多个应用&#xff0c;多窗口模式允许多个应用同时共享同一屏幕&#xff0c;多窗口模式&#xff08;Multi Window Supports&#xff09;目前支持以下三种…

在 IntelliJ IDEA 中使用 Terminal 执行 git log 命令后的退出方法

前言 IntelliJ IDEA 是一款广受欢迎的集成开发环境&#xff0c;它内置了强大的终端工具&#xff0c;使得开发者无需离开IDE就能便捷地执行各种命令行操作&#xff0c;包括使用 Git 进行版本控制。在 IDEA 的 Terminal 中执行 git log 命令时&#xff0c;由于该命令会显示项目的…

烫烫烫手的结构体大小计算来咯,很烫哦,慢慢消化。自定义类型(一)

emmm&#xff0c;在这炎热的夏天在宿舍吹着空调写着博客也是一件不错的事呢&#xff0c;今天就来来好好盘一下C语言中的自定义类型。 常常会回顾努力的自己&#xff0c;所以要给自己的努力留下足迹。 为今天努力的自己打个卡&#xff0c;留个痕迹吧 2024.03.29 小闭 目录 …

【一】DDR3基础知识与IMG IP

【一】DDR3基础知识与IMG IP 一、DDR3的基本知识 1、DDR3全称为第三代双倍速率同步动态随机存储器 特点&#xff1a;掉电无法保存数据&#xff0c;需要周期性的刷新&#xff1b;时钟上升沿和下降沿都在传输数据&#xff1b;突发传输&#xff0c;突发长度burtst length一般为…

【C++庖丁解牛】基于红黑树实现的两种常用的关联容器map和set以及multimap

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. 关联式容器2. 键值对3…

最短路径——Floyd算法、Dijkstra算法(未完...)

这里写目录标题 例题引入&#xff1a; 路径——蓝桥2021省赛题目分析题解&#xff01;&#xff01;&#xff01;求最短路径问题&#xff01;&#xff01;&#xff01;应用场景图的基础Floyd算法Acwing-843.有边数限制的最短路简单的思路讲解 Dijkstra算法 例题引入&#xff1a;…

鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

随后迎来了不少互联网公司与华为鸿蒙原生应用达成了合作&#xff0c;像我们常见的阿里、京东、小红书、得物……等公司&#xff0c;还有一些银行也都与华为鸿蒙达成了合作。使得一时之间市场紧缺鸿蒙开发人才&#xff0c;不少公司不惜重金争抢人才。 据智联招聘的最新数据显示…

最强的营销团队,这样打造!

在瞬息万变的商业环境中&#xff0c;构建无可挑剔的营销团队结构的重要性毋庸置疑。营销团队的力量不仅在于其成员的个人才能&#xff0c;还在于这些才能如何有效地协调在一起。建立完美的营销团队结构类似于拼图。每块拼图都代表了独特的技能和视角&#xff0c;如果放置得当&a…

未来5年|个人电脑“变”AI PC

随着生成式AI热潮达到白热化阶段&#xff0c;笔记本电脑市场正面临一场范式转变。根据Tech Insights预测数据&#xff0c;到2029年&#xff0c;配备专用AI加速芯片&#xff08;即NPU&#xff09;的AI赋能笔记本电脑将在整个笔记本市场占据主导地位&#xff0c;占比高达95%&…

【MySQL】事务是什么?事务的特性又是什么?

文章目录 ✍事务是什么&#xff1f;✍事务的特性&#xff08;四个&#xff09;✍事务并发时出现的问题✍事务的隔离性 ✍事务是什么&#xff1f; 事务是由一个或多个SQL语句构成的&#xff0c;在事务中&#xff0c;这些的SQL不可分割&#xff0c;是一个整体&#xff0c;整个事…

牛客NC30 缺失的第一个正整数【simple map Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/50ec6a5b0e4e45348544348278cdcee5 核心 Map参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可…

web前端之罗盘时钟、不一样的补零方式、LED字体、padStart

MENU 效果图htmlJavaScriptstyle 效果图 html <div class"clock"><div class"second-box"></div><div class"minute-box"></div><div class"hour-box"></div><div class"day-box&…

HarmonyOS 应用开发之Stage模型启动FA模型PageAbility

本小节介绍Stage模型的两种应用组件如何启动FA模型的PageAbility组件。 UIAbility启动PageAbility UIAbility启动PageAbility和UIAbility启动UIAbility的方式完全相同。 说明&#xff1a; 需注意FA模型中abilityName由bundleName AbilityName组成&#xff0c;具体见示例。 i…