Taskflow:限制最大并发度( Limit the Maximum Concurrency)

定义信号量Semaphore

Taskflow提供了一个机制,tf::Semaphore,用于限制任务部分中的最大并发。您可以让任务在执行工作之前/之后获取/释放一个或多个信号量。一项任务可以获取和释放信号量,或者只是获取或只是释放它。tf::Semaphore对象以初始计数开始。只要该计数高于0,Task就可以获得信号量并完成其工作。如果计数为0或更少,试图获取信号量的Task将不会运行,而是会进入该信号量的等待列表。当另一个Task释放信号量时,它会重新安排该等待列表中的所有任务。

#include <taskflow/taskflow.hpp>
int main() {tf::Executor executor(4); // 开启四个线程tf::Taskflow taskflow;std::vector<tf::Task> tasks {taskflow.emplace([](){ std::cout << "A" << std::endl; }),taskflow.emplace([](){ std::cout << "B" << std::endl; }),taskflow.emplace([](){ std::cout << "C" << std::endl; }),taskflow.emplace([](){ std::cout << "D" << std::endl; }),taskflow.emplace([](){ std::cout << "E" << std::endl; })};tf::Semaphore semaphore(1); // 创建一个信号量,初始值为1// 每个task在执行前尝试获取semaphore,在执行结束后释放for(auto& task : tasks) {task.acquire(semaphore);task.release(semaphore); }executor.run(taskflow).wait();
}

在这里插入图片描述
可以发现,在同一时刻,只会有一个任务被获取到semaphore并执行。

注意,用户有责任确保信号量在执行获取和释放信号量的任务时保持活力。executor和taskflow都不管理任何semaphore的生命周期。

信号量不仅能限制Task部分的最大并发性,而且限制Task不同部分的最大并发性。具体来说,您可以让一个Task获得信号量,并有另一个释放该信号量。以下示例使用信号量而不是使用显式依赖关系执行五对任务。

#include <taskflow/taskflow.hpp>
int main() {tf::Executor executor(4); // 开启四个线程tf::Taskflow taskflow;tf::Semaphore semaphore(1); // 创建一个信号量,初始值为1int n = 5, counter = 0;for(int i = 0; i < n; i++) {tf::Task f = taskflow.emplace([&](){ counter++; }).name("from-" + std::to_string(i));tf::Task t = taskflow.emplace([&](){ counter--; }).name("to-" + std::to_string(i));f.precede(t);// 隐含偏序关系:f -> tf.acquire(semaphore);t.release(semaphore);}executor.run(taskflow).wait();taskflow.dump(std::cout);
}

在这里插入图片描述
同时,因为信号量的count为1,所以同一时刻仅有一个任务在执行,且顺序一定是from-x --> to-x;
在这里插入图片描述

定义 Critical Section

tf::CriticalSection是tf::Semaphore的包装, 当Task添加到Critical Section时,该Task获取并释放Critical Section内部的信号量。此方法tf::CriticalSection::add为添加到Critical Section的每个Task自动调用tf::Task::acquire和tf::Task::release

#include <taskflow/taskflow.hpp>
int main() {tf::Executor executor(8);   // create an executor of 8 workerstf::Taskflow taskflow;// create a critical section of two workerstf::CriticalSection critical_section(2); tf::Task A = taskflow.emplace([](){ std::cout << "A" << std::endl; });tf::Task B = taskflow.emplace([](){ std::cout << "B" << std::endl; });tf::Task C = taskflow.emplace([](){ std::cout << "C" << std::endl; });tf::Task D = taskflow.emplace([](){ std::cout << "D" << std::endl; });tf::Task E = taskflow.emplace([](){ std::cout << "E" << std::endl; });critical_section.add(A, B, C, D, E);executor.run(taskflow).wait();taskflow.dump(std::cout);
}

tf::Semaphore 的一种重要应用是,有时因为任务的设计问题,任务间和任务间虽然没有显式的依赖关系,但是他们并不能在同一时刻执行(比如共享了临界区?!),如下图所示:

在这里插入图片描述

这三个Task均没有相互依赖关系,但是A和B之间同一时刻只能执行一个(谁先无所谓), 同样,A和C之间只能执行一个,而B和C没有竞争关系,可以并发执行,那么可以为这两个竞争关系各自设置一个信号量,来实现上述约束:

#include <taskflow/taskflow.hpp>
int main() {tf::Executor executor;tf::Taskflow taskflow;tf::Semaphore conflict_AB(1);tf::Semaphore conflict_AC(1);tf::Task A = taskflow.emplace([](){ std::cout << "A" << std::endl; });tf::Task B = taskflow.emplace([](){ std::cout << "B" << std::endl; });tf::Task C = taskflow.emplace([](){ std::cout << "C" << std::endl; });// describe the conflict between A and BA.acquire(conflict_AB).release(conflict_AB);B.acquire(conflict_AB).release(conflict_AB);// describe the conflict between A and CA.acquire(conflict_AC).release(conflict_AC);C.acquire(conflict_AC).release(conflict_AC);executor.run(taskflow).wait();taskflow.dump(std::cout);
}

可以看到,B和C并发执行了一段,但是A和B,A和C均不会并发执行。

在这里插入图片描述

当然,也可以使用tf::CriticalSection,简化上述逻辑:

#include <taskflow/taskflow.hpp>
int main() {tf::Executor executor;tf::Taskflow taskflow;tf::CriticalSection cs_AB(1); // tf::CriticalSection cs_AC(1);tf::Task A = taskflow.emplace([](){ std::cout << "A" << std::endl; });tf::Task B = taskflow.emplace([](){ std::cout << "B" << std::endl; });tf::Task C = taskflow.emplace([](){ std::cout << "C" << std::endl; });// describe the conflict between A and Bcs_AB.add(A,B);cs_AC.add(A,C);executor.run(taskflow).wait();taskflow.dump(std::cout);
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL介绍

1 什么是Mysql MySQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它使用结构化查询语言&#xff08;SQL&#xff09;进行数据库管理。自上世纪90年代中期以来&#xff0c;MySQL凭借其易用性、稳定性和高效性能&#xff0c;赢得了广泛的用户群体…

政安晨:【Keras机器学习实践要点】(三)—— 编写组件与训练数据

目录 介绍 编写组件 训练模型 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 介绍 通过 Ker…

手写简易操作系统(十七)--编写键盘驱动

前情提要 上一节我们实现了锁与信号量&#xff0c;这一节我们就可以实现键盘驱动了&#xff0c;访问键盘输入的数据也属于临界区资源&#xff0c;所以需要锁的存在。 一、键盘简介 之前的 ps/2 键盘使用的是中断驱动的&#xff0c;在当时&#xff0c;按下键盘就会触发中断&a…

Abaqus周期性边界代表体单元Random Sphere RVE 3D (Mesh)插件

插件介绍 Random Sphere RVE 3D (Mesh) - AbyssFish 插件可在Abaqus生成三维具备周期性边界条件(Periodic Boundary Conditions, PBC)的随机球体骨料及骨料-水泥界面过渡区(Interfacial Transition Zone, ITZ)模型。即采用周期性代表性体积单元法(Periodic Representative Vol…

1.8 python 模块 time、random、string、hashlib、os、re、json

ython之模块 一、模块的介绍 &#xff08;1&#xff09;python模块&#xff0c;是一个python文件&#xff0c;以一个.py文件&#xff0c;包含了python对象定义和pyhton语句 &#xff08;2&#xff09;python对象定义和python语句 &#xff08;3&#xff09;模块让你能够有逻辑地…

Cookie 与 Session

目录 一、获取Cookie/Session 1、理解Cookie 2、理解Session 3、Cookie 和 Session 的区别 4、获取Cookie 4.1 传统获取Cookie 4.2 简洁获取Cookie 5、Session 存储和获取 5.1 Session存储 5.2 Session读取 5.3 简洁获取 Session 一、获取Cookie/Session 1、理解Co…

【Linux】详解软硬链接

一、软硬链接的建立方法 1.1软链接的建立 假设在当前目录下有一个test.txt文件&#xff0c;要对其建立软链接&#xff0c;做法如下&#xff1a; ln就是link的意思&#xff0c;-s表示软链接&#xff0c;test.txt要建立软链接的文件名&#xff0c;后面跟上要建立的软链接文件名…

k8s1.28.8版本配置Alertmanager报警方式(邮件,企业微信)

文章目录 总结部署流程 Alertmanager 三大核心1. 分组告警2. 告警抑制3. 告警静默 报警过滤静默通知方案一&#xff1a;方案二&#xff1a; 抑制报警规则案例一 参考文档 自定义路由告警&#xff0c;分来自不同路由的告警&#xff0c;艾特不同的人员进行区分修改 alertmanager …

linux C:变量、运算符

linux C 文章目录 变量运算符 一、变量 [存储类型] 数据类型 标识符 值 标识符&#xff1a;由数字、字母、下划线组成的序列&#xff0c;不能以数字开头。 数据类型&#xff1a;基本数据类型构造类型 存储类型&#xff1a;auto static…

4月深圳振威新能源产业博览会丨千万订单采购对接会!

4月深圳振威新能源产业博览会丨千万订单采购对接会&#xff01; 目前&#xff0c;振威新能源海外招商团队已成功与俄罗斯、泰国多家组织机构建立合作联系&#xff01;已确定携多家知名企业到现场采购&#xff01; 电池与储能 同时&#xff0c;振威新能源团队也成功与泰国储能技…

【KingSCADA】播放语音

1.函数介绍 PlaySound(string strWaveFileName, int nMode);下面是官方帮助文档中的解释&#xff1a; 2.生成语音文件 3.使用脚本播放音频文件 将音频文件存放在工程目录下面&#xff0c;我存放在了…\Resources\文件夹下&#xff1a; 我简单的写了一个定时1分钟播放一次语…

Docket常见的软件部署1

1 安装MySQL # 查看MySQL镜像 docker search mysql # 拉起镜像 docker pull mysql:5.7 # 创建MySQL数据映射卷&#xff0c;防止数据不丢失 mkdir -p /hmoe/tem/docker/mysql/data/ # 启动镜像 docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /home…

蓝桥杯第七届大学B组详解

目录 1.煤球数量&#xff1b; 2.生日蜡烛&#xff1b; 3.凑算式 4.方格填数 5.四平方和 6.交换瓶子 7.最大比例 1.煤球数量 题目解析&#xff1a;可以根据题目的意思&#xff0c;找到规律。 1 *- 1个 2 *** 3个 3 ****** 6个 4 ********** 10个 不难发现 第…

OSCP靶场--Internal

OSCP靶场–Internal 考点(CVE-2009-3103) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.216.40 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-31 07:00 EDT Nmap scan report for 192.168.216.40 Host is up…

C++11新特性(二):更好用的 lambda 表达式和 function 包装器

目录 lambda 表达式 基本格式及参数列表 对于 lambda 捕捉列表的说明 function 包装器 bind 包装器 lambda 表达式 C11引入了lambda表达式&#xff0c;它是一种用于创建匿名函数的语法。lambda表达式可以被视为一个匿名函数对象&#xff0c;它可以在需要函数对象的地方使用…

PyTorch 教程-快速上手指南

文章目录 PyTorch Quickstart1.处理数据2.创建模型3.优化模型参数4.保存模型5.加载模型 PyTorch 基础入门1.Tensors1.1初始化张量1.2张量的属性1.3张量运算1.3.1张量的索引和切片1.3.2张量的连接1.3.3算术运算1.3.4单元素张量转变为Python数值 1.4Tensor与NumPy的桥接1.4.1Tens…

系统慢查询的思考

系统慢查询的思考 在一个系统中发现慢查询的功能或很卡的现象。你是怎么思考的&#xff1f;从哪几个方面去思考&#xff1f;会用什么工具&#xff1f; 一个系统使用了几年后都可能会出现这样的问题。原因可能有以下几点。 数据量的增加。系统中平时的使用中数据量是有一个累…

【AXIS】AXI-Stream FIFO设计实现(四)——异步时钟

前文介绍了几种同步时钟情况下的AXI Stream FIFO实现方式&#xff0c;一般来说&#xff0c;FIFO也需要承担异步时钟域模块间数据传输的功能&#xff0c;本文介绍异步AXIS FIFO的实现方式。 如前文所说&#xff0c;AXI-Stream FIFO十分类似于FWFT异步FIFO&#xff0c;推荐参考前…

MIPI CSI-2 Low Level Protocol解读

一、Low Level Protocol介绍 LLP 是一种面向字节的基于数据包的协议&#xff0c;支持使用短数据包和长数据包格式传输任意数据。为简单起见&#xff0c;本节中的所有示例均为单通道配置。 LLP特性&#xff1a; 传输任意数据&#xff08;与有效载荷无关&#xff09; 8 位字大…

Chatgpt掘金之旅—有爱AI商业实战篇(二)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、前言&#xff1a; 成为一名商业作者是一个蕴含着无限可能的职业选择。在当下数字化的时代&#xff0c;作家们有着众多的平台可以展示和推广自己的作品。无论您是对写书、文…