【Linux】匿名管道的应用场景-----管道进程池
目录
一、池化技术
二、简易进程池的实现:
Makefile
task.h
task.cpp
Initchannel函数:
创建任务:
控制子进程:
子进程执行任务:
清理收尾:
三、全部代码:
前言:
对于管道,我们已经学习了匿名管道,那么这个匿名管道有什么用呢?接下来,我们以池化技术来实现一个简易的管道进程池
一、池化技术
1、内存池:减少内存分配的系统调用开销
问题:
当使用new或 malloc 动态分配内存时,每次都会触发系统调用
例如:每次申请5字节,或者申请10字节,再次申请20字节,会触发三次系统调用
系统调用成本高,因为操作系统可能正在处理其他任务,导致等待,降低效率
解决方案:
一次性向操作系统申请更大的内存空间(如100字节或200字节)
后续需要内存时,直接从这块预先申请好的空间中分配,避免频繁触发系统调用
优点:
减少系统调用次数,分摊开销,提高内存分配效率
2、进程池:减少进程创建的开销
问题:
传统方式是父进程创建子进程,子进程完成任务后退出,父进程等待
每次创建子进程时,操作系统需要复制task_struct,页表等数据结构,开销较大
频繁创建和销毁进程效率低下
解决方案:
预先创建一批子进程,作为资源储备(进程池)
当有任务到来时,父进程直接将任务分配给池中已有的子进程,而不是每次都创建新进程
优点:
减少进程创建的开销,提高任务分配和执行的效率
3. 核心思想
资源预分配
无论是内存池还是进程池,核心思想都是预先分配资源,避免重复的系统调用或资源创建
提高效率:
通过减少高频操作的开销,显著提升程序性能,尤其适用于高并发或高性能场景
总结
内存池:一次性申请大块内存,后续直接从池中分配,减少系统调用
进程池:预先创建一批进程,任务到来时直接分配,减少进程创建开销
共同目标:通过资源预分配,优化性能,降低系统开销
二、简易进程池的实现:
在了解上述的池化技术后,我们以这种思想来设计一个简易的进程池
如上,这是一个简易的进程池,我们让父进程向子进程发送数据也就是父进程向管道中写入数据,然后子进程从管道中读数据,这样父进程创建多个子进程,每次选择某个子进程和管道进行数据的传输,这样就是一个简易的进程池了
Makefile
task:tesk.cppg++ -o $@ $^ -g -std=c++11
.PHONY:clean
clean:rm -f task
task.h
#pragma once #include<iostream>
#include<vector>
#include<string>
task.cpp
先描述:
首先通过class类来描述一个管道
#include"task.h"//先描述,描述管道
class channel
{
public://构造函数通过列表进行初始化channel(int fd, int childpid, const std::string &processname):_fd(fd),_childpid(childpid),_processname(processname){}
public:int _fd; //管道写端的文件描述符pid_t _childpid; //管道所连接表示子进程的pidstd::string _processname; //管道所连接的子进程的名字
};int main()
{//加载好任务//通过vector将一个个管道组织起来std::vector<channel> channels;//初始化,创建管道Initchannel(&channels);//控制子进程ctrlchild(channels);//清理收尾quitprocess(channels);return 0;
}
在组织:
在通过vector这个容器来将一个个管道组织起来,然后进行初始化,控制子进程,清理等操作
Initchannel函数:
创建管道,这个管道是连接父进程和子进程的,所以我们要创建几个管道就需要创建几个子进程
通过pipe创建管道文件
初始化:
void Initchannel(std::vector<channel>* channels)
{for(int i = 0;i<processnum;i++){//创建管道int pipefd[2];int n = pipe(pipefd);//创建管道文件if(n != 0) exit(0);//创建失败就退出程序//创建完管道文件然后创建管道文件对应的子进程pid_t id = fork();if(id == 0){//子进程模块,这里子进程去读,所以关闭写通道close(pipefd[1]);//重定向dup2(pipefd[0],0);work();//子进程进行工作的函数模块exit(0);//工作完就结束子进程}//父进程去写所以这里关闭读端close(pipefd[0]);std::string name = "process"+std::to_string(i);channels->push_back(channel(pipefd[1],id,name));}
}
创建任务:
//重定义函数指针
typedef void(* task)();void task1()
{std::cout<<"刷新野区"<<std::endl;
}void task2()
{std::cout<<"刷新技能"<<std::endl;
}void task3()
{std::cout<<"泉水回血"<<std::endl;
}void task4()
{std::cout<<"技能耗蓝"<<std::endl;
}void Loadtask(std::vector<task>* tasks)
{tasks->push_back(task1);tasks->push_back(task2);tasks->push_back(task3);tasks->push_back(task4);
}
其中Loadtask函数的作用就是保存所执行的任务
接着在程序最开始(也就是在main函数的最开始),将我们的任务都进行加载好
还需要全局变量
processnum:
控制进程池的大小,决定创建多少个子进程。
方便扩展,例如通过配置文件动态设置子进程数量。
tasks:
集中管理所有任务,便于父进程和子进程共享任务列表。
通过任务码(索引)快速定位和执行任务。
const int processnum = 5;//进程中子进程的数量
std::vector<task> tasks;//存储任务的容器int main()
{//加载好任务Loadtask(&tasks);//通过vector将一个个管道组织起来std::vector<channel> channels;//初始化,创建管道Initchannel(&channels);//控制子进程ctrlchild();//清理收尾quitprocess();return 0;
}
手动控制子进程
这里首先搞一个菜单出来
void menu()
{std::cout << "#########################################" << std::endl;std::cout << "# 1、刷新野区 2、刷新技能 #" << std::endl;std::cout << "# 3、泉水回血 4、技能耗蓝 #" << std::endl;std::cout << "# 0、退出 #" << std::endl;std::cout << "#########################################" << std::endl;
}
在控制子进程的过程中,我们首先选好我们要完成的任务,然后向管道里写一个任务码,然后被选中的子进程就会从管道中找到任务码,就可以根据vector<task>里面的任务知道需要执行哪一个任务了
控制子进程:
根据菜单,每次输入任务码的时候,就通过write系统调用来确定子进程,发送任务
void ctrlchild(std::vector<channel>& channels)
{int which = 0;while(1){menu();int selet = 0;std::cout<<"请输入所选择的任务";std::cin>>selet;//判断所选的任务码是否合法if(selet<=0 || selet>=5) break;//任务选择int taskcode = selet - 1;//子进程选择,轮询法std::cout<<"father say taskcode :" << taskcode <<" already send to " << channels[which]._childpid << "process name " << channels[which]._processname << std::endl;//发送任务write(channels[which]._fd,&taskcode,sizeof(taskcode));//确定子进程,子进程所接收的任务码,和所接受的大小//保证所选的进程合法which++;which %= channels.size();}
}
子进程执行任务:
这是子进程的核心代码,通过read系统调用接口从管道中读到任务码,在通过这个任务码和函数指针来调用任务
//子进程工作代码,通过父进程向管道发送的任务码找到对应的任务,然后执行
void work()
{while(1){int teskcode = 0;int n = read(0, &teskcode, sizeof(teskcode)); //read返回的是读取到的字节的个数。 //然后第二个参数是要读到哪里去,第三个参数是读取的大小,这一行代码执行完后,teskcode里面保存的就是要执行的任务码if (n == sizeof(teskcode)){std::cout << "work get a command : " << getpid() << " : " << "teskcode" << teskcode << std::endl;if (teskcode >= 0 && teskcode < tasks.size()) tasks[teskcode]();}if (n == 0) break; //如果读到0, 说明写端关闭, 读端读到文件末尾, 就需要停止读取了}
}
清理收尾:
在清理收尾的时候不能够直接关闭然后父进程等待子进程,这样是有问题的,因为当父进程创建子进程的时候,子进程的读端也会指向对应的管道,这样的话一个管道就会有很多个读端了,如下:
每一个子进程的写端都会指向之前的所有管道,比如,如果上述有3个进程的话,那么第一个管道就有3个写端(父进程一个,父进程创建的两个子进程的写端都会指向第一个管道),那么如果直接close(c._fd)关闭管道的写端的话,那么是不能够关闭完全的,需要全部关闭,这里有两种解决方式:
第一种方式:
从后往前进行关闭,下面代码已给出,我们知道最后一个管道依然是只有一个写端的,那么当最后一个管道关闭后,前面的管道的写端就都会少一个,这样的话从后往前关闭就不会出现这样的问题了
void quitprocess(const std::vector<channel> &channels)
{//出现问题for(const auto &c : channels){close(c._fd); waitpid(c._childpid,nullptr,0);}// //解决方案1// int last = channels.size()-1;// for(int i = last;i>=0;i--)// {// close(channels[i]._fd);// waitpid(channels[i]._childpid,nullptr,0);// }// for(const auto &c : channels)// {// close(c._fd);// }// for(const auto &c : channels)// {// waitpid(c._childpid,nullptr,0);// }
}
第二种方式:
在创建管道的时候进行记录父进程所占用的文件描述符
三、全部代码:
makefile
task:task.cppg++ -o $@ $^ -g -std=c++11
.PHONY:clean
clean:rm -f task
task.h
#pragma once #include<iostream>
#include<vector>
#include<string>#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>//重定义函数指针
typedef void(* task)();void task1()
{std::cout<<"刷新野区"<<std::endl;
}void task2()
{std::cout<<"刷新技能"<<std::endl;
}void task3()
{std::cout<<"泉水回血"<<std::endl;
}void task4()
{std::cout<<"技能耗蓝"<<std::endl;
}//保存所执行的任务
void Loadtask(std::vector<task>* tasks)
{tasks->push_back(task1);tasks->push_back(task2);tasks->push_back(task3);tasks->push_back(task4);
}
task.cpp
#include"task.h"const int processnum = 5;
std::vector<task> tasks;
//先描述,描述管道
class channel
{
public://构造函数通过列表进行初始化channel(int fd, int childpid, const std::string &processname):_fd(fd),_childpid(childpid),_processname(processname){}
public:int _fd; //表示父进程链接某个管道的fdpid_t _childpid; //管道所连接表示子进程的pidstd::string _processname; //管道所连接的子进程的名字
};//子进程工作代码,通过父进程向管道发送的任务码找到对应的任务,然后执行
void work()
{while(1){int teskcode = 0;int n = read(0, &teskcode, sizeof(teskcode)); //read返回的是读取到的字节的个数。 //然后第二个参数是要读到哪里去,第三个参数是读取的大小,这一行代码执行完后,teskcode里面保存的就是要执行的任务码if (n == sizeof(teskcode)){std::cout << "work get a command : " << getpid() << " : " << "teskcode" << teskcode << std::endl;if (teskcode >= 0 && teskcode < tasks.size()) tasks[teskcode]();}if (n == 0) break; //如果读到0, 说明写端关闭, 读端读到文件末尾, 就需要停止读取了}
}void Initchannel(std::vector<channel>* channels)
{//解决方案2std::vector<int> oldfd;//创建一个数组记录父进程所在的文件描述符的写端for(int i = 0;i<processnum;i++){//创建管道int pipefd[2];int n = pipe(pipefd);//创建管道文件if(n != 0) exit(0);//创建失败就退出程序//创建完管道文件然后创建管道文件对应的子进程pid_t id = fork();if(id == 0){//将父进程所在的文件描述符写端,子进程将其关闭for(auto fd : oldfd) close(fd);//子进程模块,这里子进程去读,所以关闭写通道close(pipefd[1]);//重定向dup2(pipefd[0],0);work();//子进程进行工作的函数模块std::cout << "Process PID: " << getpid() << " quit" << std::endl;exit(0);//工作完就结束子进程}//父进程去写所以这里关闭读端close(pipefd[0]);std::string name = "process"+std::to_string(i);channels->push_back(channel(pipefd[1],id,name));//每次记录父进程写端所在的文件描述符oldfd.push_back(pipefd[1]); }
}void menu()
{std::cout << "#########################################" << std::endl;std::cout << "# 1、刷新野区 2、刷新技能 #" << std::endl;std::cout << "# 3、泉水回血 4、技能耗蓝 #" << std::endl;std::cout << "# 0、退出 #" << std::endl;std::cout << "#########################################" << std::endl;
}void ctrlchild(std::vector<channel>& channels)
{int which = 0;while(1){menu();int selet = 0;std::cout<<"请输入所选择的任务";std::cin>>selet;//判断所选的任务码是否合法if(selet<=0 || selet>=5) break;//任务选择int taskcode = selet - 1;//子进程选择,轮询法std::cout<<"father say taskcode :" << taskcode <<" already send to " << channels[which]._childpid << "process name " << channels[which]._processname << std::endl;//发送任务write(channels[which]._fd,&taskcode,sizeof(taskcode));//确定子进程,子进程所接收的任务码,和所接受的大小//保证所选的进程合法which++;which %= channels.size();}
}void quitprocess(const std::vector<channel> &channels)
{//出现问题for(const auto &c : channels){close(c._fd); waitpid(c._childpid,nullptr,0);}// //解决方案1// int last = channels.size()-1;// for(int i = last;i>=0;i--)// {// close(channels[i]._fd);// waitpid(channels[i]._childpid,nullptr,0);// }// for(const auto &c : channels)// {// close(c._fd);// }// for(const auto &c : channels)// {// waitpid(c._childpid,nullptr,0);// }
}int main()
{//加载好任务Loadtask(&tasks);//通过vector将一个个管道组织起来std::vector<channel> channels;//初始化,创建管道Initchannel(&channels);//控制子进程ctrlchild(channels);//清理收尾quitprocess(channels);return 0;
}
相关文章:
【Linux】匿名管道的应用场景-----管道进程池
目录 一、池化技术 二、简易进程池的实现: Makefile task.h task.cpp Initchannel函数: 创建任务: 控制子进程: 子进程执行任务: 清理收尾: 三、全部代码: 前言: 对于管…...
umi react+antd 判断渲染消息提示、input搜索、多选按钮组
记得map里返回的每层遍历结构都要带上key(图里没加,最近在接手react,熟悉中......
Windows桌面系统管理5:Windows 10操作系统注册表
Windows桌面系统管理0:总目录-CSDN博客 Windows桌面系统管理1:计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2:VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3:Windows 10操作系统部署与使用-CSDN博客 Wi…...
华为昇腾 910B 部署 DeepSeek-R1 蒸馏系列模型详细指南
本文记录 在 华为昇腾 910B(65GB) * 8 上 部署 DeepSeekR1 蒸馏系列模型(14B、32B)全过程与测试结果。 NPU:910B3 (65GB) * 8 (910B 有三个版本 910B1、2、3) 模型:DeepSeek-R1-Distill-Qwen-14B、DeepSeek…...
文献阅读 250219-Global water availability boosted by vegetation-driven changes (1)
Global water availability boosted by vegetation-driven changes in atmospheric moisture transport 来自 <https://www.nature.com/articles/s41561-022-01061-7> ## Abstract: 全球水资源的可用性是气候变化研究中的重要议题,尤其是随着气候变化的加剧&a…...
蓝桥杯篇---超声波距离测量频率测量
文章目录 简介第一部分:超声波的简介工作原理1.发射超声波2.接收反射波3.计算时间差4.计算距离 硬件连接1.Trig2.Echo 示例代码代码说明注意事项1.声速2.延时精度3.硬件连接 第二部分:频率测量简介频率测量原理1.信号输入2.计数3.计算频率 硬件连接示例代…...
【玩转 Postman 接口测试与开发2_020】(完结篇)DIY 实战:随书示例 API 项目本地部署保姆级搭建教程(含完整调试过程)
《API Testing and Development with Postman》最新第二版封面 文章目录 最新版《Postman 接口测试与开发实战》示例 API 项目本地部署保姆级搭建教程1 前言2 准备工作3 具体部署3.1 将项目 Fork 到自己名下3.2 创建虚拟环境并安装依赖3.3 初始运行与项目调试 4 示例项目的用法…...
LearnOpenGL——高级OpenGL(下)
教程地址:简介 - LearnOpenGL CN 高级数据 原文链接:高级数据 - LearnOpenGL CN 在OpenGL中,我们长期以来一直依赖缓冲来存储数据。本节将深入探讨一些操作缓冲的高级方法。 OpenGL中的缓冲本质上是一个管理特定内存块的对象,它…...
wangEditor 编辑器 Vue 2.0 + Nodejs 配置
资料 Vue2.0 版本的安装:https://www.wangeditor.com/v5/for-frame.html#%E4%BD%BF%E7%94%A8上传图片配置:https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87 安装步骤 1.安装界面基础部分 <!-- 富文本编辑器…...
机器学习·数据处理
前言 对于大规模数据,我们经常会使用python内置函数或者编写脚本进行批量化处理,从而提高后续使用算法的效率。 1. 正则表达式 定义:用于检索、替换符合某个模式的文本,是文本预处理常用技术。基本语法 符号描述.匹配除换行符 …...
如何在Bigemap Pro中用线分割面、挖空
有时候需要以一条线为界对面元素进行分割或者是需要在一个面元素里面挖空一个面形状的洞,对此需求可以使用bigemap pro工具实现,这里为你介绍一下具体的操作方法。 【一】画线分割面 第一步:现在这是一个不规则多边形,想要以手动…...
网络安全入门攻击与防御实战(四)
漏洞利用:永恒之蓝(MS17-010)与同类漏洞解析 1 永恒之蓝(MS17-010)漏洞背景 (1)漏洞信息 CVE编号:CVE-2017-0143 ~ CVE-2017-0148 影响范围:Windows XP ~ Windows 201…...
DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)
前言 在当今数字化时代,AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型,凭借其出色的性能和开源免费的优势,成为许多开发者的首选。今天,就让我们一起探索如何将DeepSeek接入PyCharm,实现高效、智…...
CF1801D
CF1801D 题目大意: n n n 个顶点, m m m 条边的图。你一开始在起点 1,拥有 P P P 枚硬币,通过每条 ( i , j ) (i,j) (i,j) 边都需要花费一定的硬币 s ( i , j ) s(i,j) s(i,j)。但你在每个城市 i i i 都可以打工赚硬币 w i w…...
大厂算法面试常见问题总结:高频考点与备战指南
在大厂算法面试中,数据结构与算法是必考的核心内容。 无论是校招还是社招,算法题的表现往往决定了面试的成败。 为了帮助大家更好地备战,本文总结了大厂算法面试中的高频考点,并提供了详细的备战建议,助你轻松应对面…...
【R语言】主成分分析与因子分析
一、主成分分析 主成分分析(Principal Component Analysis, PCA)是一种常用的无监督数据降维技术,广泛应用于统计学、数据科学和机器学习等领域。它通过正交化线性变换将(高维)原始数据投影到一个新的坐标系ÿ…...
解锁 AIoT 无限可能,乐鑫邀您共赴 Embedded World 2025
2025 年 3 月 11-13 日,全球规模最大的嵌入式展览会——Embedded World 2025 将在德国纽伦堡盛大开幕。作为物联网和嵌入式技术领域的领先企业,乐鑫信息科技 (688018.SH) 将展示在 AI LLM、HMI、双频 Wi-Fi 6、低功耗 MCU 和 Matter 等领域的最新技术及解…...
人工智能基础之数学基础:01高等数学基础
函数 极限 按照一定次数排列的一列数:“,“,…,"…,其中u 叫做通项。 对于数列{Un}如果当n无限增大时,其通项无限接近于一个常数A,则称该数列以A为极限或称数列收敛于A,否则称数列为发散, 极限值 左…...
【从0做项目】Java搜索引擎(8) 停用词表 正则
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 文章导读 零:项目结果展示 一:前引 二:停用词表 1:…...
线程和进程的区别
如果说一个服务器同一时刻收到了许多请求,针对每一个请求,操作系统都会产生一个进程,从而给这个请求提供一些服务 ,返回响应,如果请求处理完了,这个进程就要销毁了!如果请求很多的话,…...
深入理解 QObject的作用
QObject 作为 Qt 库中所有对象的基类,其地位无可替代。几乎 Qt 框架内的每一个类,无论是负责构建用户界面的 QWidget,还是专注于数据处理与呈现的 QAbstractItemModel,均直接或间接继承自 QObject。这种继承体系赋予 Qt 类库高度的…...
解码 NLP:从萌芽到蓬勃的技术蜕变之旅
内容概况: 主要讲述NLP专栏的内容和NLP的发展及其在现代生活中的广泛应用。课程强调实践为主、理论为辅的学习方法,并通过多个生活场景展示了NLP技术的实际应用,如对话机器人、搜索引擎、翻译软件、电商推荐和智能客服等。 这边我就不多做自我…...
【核心算法篇十五】《深度解析DeepSeek遗传算法:让超参数调优从“玄学”变“科学”的终极指南》
引言:超参数调优的“炼丹困局”与破局之路 在机器学习的世界里,调参工程师常被戏称为"炼丹师"——面对动辄几十个超参数的复杂模型,我们就像古代术士守着炼丹炉,不断尝试各种参数组合,期待偶然炼出"仙丹"。传统网格搜索(Grid Search)需要遍历所有可…...
Python—变量、基本数据类型、类型的转换
文章目录 Python—变量、基本数据类型1 格式化输出2 号的使用3 变量的数据类型4 type() 函数的使用5 数据类型的基本介绍5.1 int 整型5.2 float 浮点类型5.3 bool 布尔类型5.4 str 字符串类型5.5 字符串驻留机制5.6 数据类型的转换(1)隐式转换ÿ…...
启明星辰规则库下载
启明星辰规则库下载 一、脚本介绍 1、背景介绍 因为项目上有启明星辰的安全设备、并且在内网无法直接连接互联网进行在线升级,必须使用离线升级模式,下载规则库升级,每月一更有点繁琐,所以写了这个b脚本,偷懒一下&a…...
uniapp 拖拽排序
1.拖拽排序 使用 sortablejs库 npm install sortablejs --save-dev <template><view id"list"><view v-for"(item, index) in list" :key"item.id" class"item">{{ item.name }}</view></view> </t…...
测试。。。
移动到中位数位置能保证总移动距离最小,数学知识 #include <iostream> #include <vector> #include <cmath> using namespace std;int main() {int n;string s;cin >> n >> s;vector<int> positions;// 记录所有1的位置for (…...
Java常用设计模式及其应用场景
1. 什么是设计模式? 设计模式是一个经过多次验证的、针对常见问题的可复用解决方案。设计模式并不是具体的代码实现,而是给出了如何解决问题的思路和结构。在实际开发过程中,设计模式有助于开发者快速找到合适的解决方案,从而减少…...
2000字,极简版华为数字化转型方法论
作为国内科技行业的领军者,华为的成功经验为众多企业提供了宝贵的借鉴。本文将围绕准备、规划和执行三个阶段展开,结合华为的实践案例,深入剖析其数字化转型的方法论,希望能为您的企业数字化转型提供有益的参考。 一、数字化转型…...
Ubuntu:20.04更新cmake到更高版本
从输出信息可以看出,您当前的系统中已经安装了 cmake,但版本是 3.16.3,而您的项目需要 CMake 3.18 或更高版本。默认情况下,Ubuntu 20.04 的官方软件仓库中提供的 CMake 版本较低(如 3.16.3),因…...
【SpringBoot教程】Spring Boot + MySQL + Druid连接池整合教程
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 前面毛毛张介绍过HikariCP连接池,今天毛毛张来介绍一下Druid连接池,SpringBoot 2.0以上默认使用HikariCP数据源,但是也要学会使用…...
基于SpringBoot实现的宠物领养系统平台功能一
一、前言介绍: 1.1 项目摘要 宠物领养需求增加:随着人们生活水平的提高和对宠物养护意识的增强,越来越多的人选择领养宠物作为家庭的一员。这导致了宠物领养需求的显著增加。 传统领养方式存在问题:传统的宠物领养方式…...
【DeepSeek 学C++】std::atomic 用于线程控制,和内存强顺序一致性
std::atomic<bool> workerTerminate_{}; std::atomic<bool> workerTerminate_{}; 是一个原子布尔变量的声明,变量名为 workerTerminate_。这种变量通常用于多线程编程中,用来控制或通知工作线程的终止。使用 std::atomic 可以确保对该变量的…...
计算存储一幅大小为 1024×10241024×1024、256 灰度级的图像所需的字节数
1. 图像的基本信息 图像分辨率:1024102410241024,表示图像有 1024 行和 1024 列,总像素数为: 102410241,048,576 像素102410241,048,576 像素 灰度级:256 灰度级,表示每个像素的灰度值可以用 256 个不同的值…...
Flutter 网络请求与数据处理:从基础到单例封装
Flutter 网络请求与数据处理:从基础到单例封装 在 Flutter 开发中,网络请求是一个非常常见的需求,比如获取 API 数据、上传文件、处理分页加载等。为了高效地处理网络请求和数据管理,我们需要选择合适的工具并进行合理的封装。 …...
从开发到部署:EasyRTC嵌入式视频通话SDK如何简化实时音视频通信的集成与应用
嵌入式设备和视频综合管理平台均支持B/S架构。在B/S架构下,传统的视频观看方式依赖于微软的OCX控件,然而OCX控件的使用正面临越来越多的挑战: 首先,用户需要安装浏览器插件、调整浏览器安全级别,并允许ActiveX控件弹出…...
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300的秘密武器
嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 企业级应用开发的需求日益增长。今天,我们要介绍的是一个在GitHub上广受好评的开源项目——Jeesite5。这不仅是一个技术框架,更…...
C++(23):lambda可以省略()
C越来越多的使用了lambda,C23也进一步的放宽了对lambda的限制,这一次,如果lambda没有参数列表,那么可以直接省略掉(): #include <iostream> using namespace std;void func() {auto f []{cout<<"in…...
vue3之echarts柱状图-圆锥加自动轮播
vue3之echarts柱状图-圆锥加自动轮播 效果: 版本 "echarts": "5.4.2" 核心代码: <template><div ref"echartRef" class"chart"></div><svg><linearGradient v-for"(item, i…...
Qt中利用httplib调用https接口
httplib中如果要调用https接口,需要开启OPENSSL支持,经过半天坑爹得摸索,总结下经验。 1,下载 并安装Win64OpenSSL 地址如下,我Qt版本是5.15.2 ,openssl选择的是 64位(Win64OpenSSL-3_3_3.msi…...
深度学习04 数据增强、调整学习率
目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换(如旋转、翻转、裁剪等)&am…...
卷积神经网络之AlexNet经典神经网络,实现手写数字0~9识别
深度学习中较为常见的神经网络模型AlexNet,AlexNet 是一个采用 GPU 训练的深层 CNN,本质是种 LeNet 变体。由特征提取层的5个卷积层两个下采样层和分类器中的三个全连接层构成。 先看原理: AlexNet网络特点 采用 ReLU 激活函数,…...
建筑兔零基础自学python记录22|实战人脸识别项目——视频人脸识别(下)11
这次我们继续解读代码,我们主要来看下面两个部分; 至于人脸识别成功的要点我们在最后总结~ 具体代码学习: #定义人脸名称 def name():#预学习照片存放位置path M:/python/workspace/PythonProject/face/imagePaths[os.path.join(path,f) f…...
全球化趋势下中资企业出海投资及合规运营实战分享
企业全球化布局需构建“战略-架构-合规-运营”四位一体体系,通过灵活的投资架构、精准的税务规划、本土化运营和ESG融合,实现风险可控的海外扩张。核心策略包括: 供应链多节点布局(至少3个国家备份产能);融…...
2025-2-19 leetcode刷题情况(二叉树)
一、226.翻转二叉树 1.题目描述 给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点 2.代码 3.思路 递归遍历(DFS)交换每个节点的左 / 右子节点,即可生成二叉树的镜像。 递归解析: 终止条件&a…...
Linux常见命令
文件和目录操作命令 cd:用于切换目录。例如,cd /home/user 可进入 /home/user 目录;cd.. 可返回上一级目录。ls:用于列出目录内容。ls 直接列出当前目录下的文件和文件夹;ls -l 以详细列表形式显示;ls -a 显…...
C++ 一篇读懂“值传递”和“地址传递”
让我们通过一个简单的、形象的比喻来帮助你理解“值传递”和“地址传递”是如何影响实参的。 1. 值传递 想象你有一个 **信封**(代表变量),里面放着一张纸条(代表数据)。你决定把这个信封寄给一个朋友,让他…...
我用AI做数据分析之数据清洗
我用AI做数据分析之数据清洗 AI与数据分析的融合效果怎样? 这里描述自己在使用AI进行数据分析(数据清洗)过程中的几个小故事: 1. 变量名的翻译 有一个项目是某医生自己收集的数据,变量名使用的是中文,分…...
韩国哈希散列算法DHA-256
韩国哈希散列算法DHA-256 DHA-256是在2005年11月由NIST举行的Hash研讨会(Cryptographic Hash Workshop)上提出的。DHA-256压缩函数将长度为512比特的分组,压缩成长度为256比特的串,总共迭代64步,扩展的消息字在步函数中使用了两次。 DHA-25…...
【愚公系列】《Python网络爬虫从入门到精通》022-Splash的爬虫应用
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…...