当前位置: 首页 > news >正文

进程通信(进程池的模拟实现) read write函数复习 Linux ─── 第23课

目录

进程池(process pool)

第一步: 创建并初始化processpool

第二步:主进程对子进程派发任务

补充:

第三步: 子进程执行完退出进程池

回收子进程

进程池的实现

Channel.hpp

ProcessPool.hpp

Task.hpp

main.cc

makefile


匿名管道的应用: 进程池

进程池(process pool)

先把进程创建出来,需要什么任务 ,派发什么任务.

让一个进程(master进程) ,给其他进程(work进程)派发任务 

下面实现process pool

第一步: 创建并初始化processpool

master要管理所有的管道 创建channel

创建管道 ,创建子进程 ,用vector管理全部的channel 

#include<iostream>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<vector>
#include<functional>//执行任一方法//typedef std::function<void()> work_t;
using work_t =std::function<void()>;//定义了函数对象类型enum 
{OK=0,UsageError,PipeError,ForkError,CloseError,Dup2Error
};//先描述
class channel
{
public:channel(int wfd ,pid_t who):_wfd(wfd),_who(who){_name ="channel-"+std::to_string(wfd)+"->"+ std::to_string(who);}~channel(){}std::string Name(){return _name;}
private:int _wfd;std::string _name;//channel-3->203444pid_t _who;
};void Worker()
{//read ->stdin
}
void Download()
{//read ->stdin
}//channels是输出型参数
//work_t work 回调方法   使创建子进程与让子进程执行任务是解耦的
int InitProcessPool(std::vector<channel>& channels ,int num ,work_t work)
{//创建指定进程个数for(int i=0 ;i <num; i++){   //管道int Pipefds[2]={0};int n =::pipe(Pipefds);if(n< 0) return PipeError;//子进程pid_t id =::fork();if(id == 0){//child 读int close_ret = ::close(Pipefds[1]);//关闭写通道if(close_ret < 0) return CloseError;int dup2_ret =::dup2(Pipefds[0] ,0);//重定向,让子进程从标准输入中获取要执行的任务。不再使用Pipefds[0]了      if(dup2_ret< 0) return Dup2Error;work();::close(Pipefds[0]);//sleep(10);  DebugPrint用::exit(0);}else if(id < 0){return ForkError;}else{//parentint close_ret = ::close(Pipefds[0]);//关闭读通道if(close_ret < 0) return CloseError;channels.emplace_back(Pipefds[1] , id);}}return OK;}
void DebugProcesspool(std::vector<channel>& channels)
{for( auto &c :channels){std::cout<< c.Name() <<std::endl;}}void Usage(std::string process)
{std::cout<<"Uasge:"<< process <<"process-num"<<std::endl;
}//我们自己是master
int main(int argc ,char* argv[])
{if(argc!=2){Usage(argv[0]);return UsageError;}int num  =std::stoi(argv[1]);std::vector<channel> channels;//1.创建&&初始化进程池InitProcessPool(channels , num ,Worker);// InitProcessPool(channels , num ,Print);// InitProcessPool(channels , num ,Dowload);//DebugProcesspool(channels);sleep(100);return 0;
}

第二步:主进程对子进程派发任务

补充:

        什么是任务? 任务码表示任务  4个字节(int)写 ,4个字节(int)读  

        怎么派发? 让每个子进程任务量相等   

  • 方法1: 轮询
  • 方法2:随机
  • 方法3:历史任务数

第三步: 子进程执行完退出进程池

派发完所有的任务,子进程读取完 ,都在read阻塞 ,此时关闭子进程的两种方法

  1. 向子进程发送退出任务
  2. 利用管道写端关闭,读端读到0 ,子进程会自己退出的特性(推荐)

回收子进程

这里有一个藏得很深的bug

        在创建多管道时 ,子进程会继承父进程的fd表 ,就会导致管道的写端被越来越多的子进程拿到,引用计数++ ,释放master进程的全部的wfd后 ,管道的写端还链接着子进程 ,就不能使上面的方法2成功,

解决方法: 

  1. 倒着关闭master的wfd(最后一个管道只有一个wfd(在master,子进程都没有最后一个管道的wfd) ,倒着关闭子进程 ,此子进程的wfd也会跟着关闭)
  2. 在创建子进程时关闭历史wfd

通过上图发现父进程的_wfd从4开始递增

子进程的_rfd都是3

进程池的实现

Channel.hpp


#ifndef __CHANNEL_HPP__
#define __CHANNEL_HPP__#include <iostream>
#include <string>
#include <unistd.h>//先描述
class channel
{
public:channel(int wfd ,pid_t who):_wfd(wfd),_who(who){_name =" channel-"+std::to_string(wfd)+"->"+ std::to_string(who);}~channel(){}void Send(int tasknum){::write(_wfd ,&tasknum ,sizeof(tasknum)); //write第二个参数是const void *buf}std::string Name(){return _name;}void Close(){::close(_wfd);}pid_t Id(){return _who;}int WFD(){return _wfd;}
private:int _wfd;std::string _name;//channel-3->203444pid_t _who;
};#endif

ProcessPool.hpp

#include<iostream>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<vector>
#include<functional>//执行任一方法
#include"Task.hpp"
#include"Channel.hpp"enum 
{OK=0,UsageError,PipeError,ForkError,CloseError,Dup2Error
};
//typedef std::function<void()> work_t;
using work_t =std::function<void()>;//定义了函数对象类型class ProcessPool
{
public:ProcessPool(int num ,work_t w):num(num),work(w){}//channels是输出型参数
//work_t work 回调方法   使创建子进程与让子进程执行任务是解耦的
int InitProcessPool()
{//创建指定进程个数for(int i=0 ;i <num; i++){   //管道int Pipefds[2]={0};int n =::pipe(Pipefds);if(n< 0) return PipeError;//子进程pid_t id =::fork();if(id == 0){//child 读// 子进程关闭历史wfdfor(auto &c : channels){std::cout  << c.WFD() << " ";c.Close();}int close_ret = ::close(Pipefds[1]);//关闭写通道if(close_ret < 0) return CloseError;int dup2_ret =::dup2(Pipefds[0] ,0);//重定向,让子进程从标准输入中获取要执行的任务。不再使用Pipefds[0]了      if(dup2_ret< 0) return Dup2Error;//子进程从管道拿任务 ,执行任务work();//work()退出后exit::close(Pipefds[0]);//sleep(10);  DebugPrint用::exit(0);}else if(id < 0){return ForkError;}else{//parentint close_ret = ::close(Pipefds[0]);//关闭读通道if(close_ret < 0) return CloseError;channels.emplace_back(Pipefds[1] , id);}}return OK;}void DebugProcesspool(){for( auto &c :channels){std::cout<< c.Name() <<std::endl;}}void DispathTask()
{int who =0;//派发任务int num =20; //20个任务while(num--){//a.选择一个任务 ,整数值  ,taskmanager中选int Tasknum = TM.SelectTask();//b.选择一个子进程管道  ,channels中选channel &curr =channels[who++];who %= channels.size();std::cout<<"######################"<<std::endl;std::cout<<"send"<<Tasknum<<" "<<curr.Name()<<"任务还剩"<<num<<std::endl;std::cout<<"######################"<<std::endl;//c.通过管道派发任务curr.Send(Tasknum);sleep(1);}}void CleanProcesspool()
{// version 3  前提:子进程创建时删除了继承自master的历史wfdfor (auto &c : channels){c.Close();pid_t rid = ::waitpid(c.Id(), nullptr, 0);if (rid > 0){std::cout << "child " << rid << " wait ... success" << std::endl;}}// version 2  前提:子进程创建时没有删除继承自master的历史wfd   方法:倒着关闭master的wfd(让最后一个子进程先读到0,关闭读端 Worker退出 子进程退出)// for(int i = channels.size()-1; i >= 0; i--)// {//     channels[i].Close();//     pid_t rid = ::waitpid(channels[i].Id(), nullptr, 0); // 阻塞了!//     if (rid > 0)//     {//         std::cout << "child " << rid << " wait ... success" << std::endl;//     }// }//vertion1// for(auto& c :channels)// {//     c.Close();// }// //回收子进程,为啥写两个循环// for(auto &c:channels)// {//     int n =waitpid(c.Id() ,nullptr ,0);//     if(n > 0)//     {//         std::cout<<"wait child:"<< n <<"sucess  "<<std::endl;//     }// }
}private:std::vector<channel> channels;int num ;work_t work;
};

Task.hpp

#pragma once#include<iostream>
#include<unordered_map>
#include<functional>
#include<ctime>
#include <sys/types.h>
#include <unistd.h>
using work_t =std::function<void()>;void Download()
{std::cout<<"我是Download任务 "<<"我的pid是"<<getpid()<<std::endl;
}
void Print()
{std::cout<<"我是Print任务 "<<"我的pid是"<<getpid()<<std::endl;
}
void Log ()
{std::cout<<"我是Log日志任务 "<<"我的pid是"<<getpid()<<std::endl;
}
void Sql()
{std::cout<<"我是Sql数据库同步任务 "<<"我的pid是"<<getpid()<<std::endl;
}static int  num =0;//总任务个数
class TaskManager
{
public:TaskManager(){srand(time(nullptr));InsertTask(Download);InsertTask(Print);InsertTask(Log);InsertTask(Sql);}void InsertTask(work_t t){_tasks[num++] =t;}//选择任务int SelectTask(){return rand()% num;}void Excute(int number){//没有这个任务if(_tasks.find(number) == _tasks.end()) return;//有这个任务 ,执行_tasks[number]();}~TaskManager(){}private:std::unordered_map<int ,work_t> _tasks;
};TaskManager TM;//Task属于父子共享区//子进程的回调方法
void Worker()
{//read ->stdinwhile(true){int cmd =0;int n =::read( 0, &cmd ,sizeof(cmd));//读和写都是以一个int的大小if( n== sizeof(cmd))//执行任务{TM.Excute(cmd);}else if(n == 0)//读端已经读到0啦代表写端已经关闭 ,关闭子进程{std::cout<<"pid:"<<getpid()<<"quit..."<<std::endl;break;}else{}}
}

main.cc

#include"ProcessPool.hpp"
#include"Task.hpp"void Usage(std::string process)
{std::cout<<"Uasge:"<< process <<"process-num"<<std::endl;
}//我们自己是master
int main(int argc ,char* argv[])
{if(argc!=2){Usage(argv[0]);return UsageError;}int num  =std::stoi(argv[1]);ProcessPool * pp = new ProcessPool(num ,Worker); //1.创建&&初始化进程池pp->InitProcessPool();//2.派发任务pp->DispathTask();//3.退出进程池 ,只需要关闭所有管道的写端即可pp->CleanProcesspool();//1.创建&&初始化进程池//InitProcessPool(channels , num ,Worker);//DebugProcesspool(channels);//2.派发任务//DispathTask(channels);//3.退出进程池 ,只需要关闭所有管道的写端即可//CleanProcesspool(channels);delete(pp);return 0;
}

makefile

BIN=processpool
CC=g++
FLAGS=-c -Wall -std=c++11
LDFLAGS= -o
#SRC=$(shell ls *.cc)
SRC=$(wildcard *.cc)
OBJ=$(SRC:.cc=.o)$(BIN):$(OBJ)$(CC) $(LDFLAGS) $@ $^
%.o:%.cc$(CC) $(FLAGS)  $<.PHONY:clean
clean:rm -f $(BIN) $(OBJ).PHONY:test
test:@echo $(SRC)@echo $(OBJ)

相关文章:

进程通信(进程池的模拟实现) read write函数复习 Linux ─── 第23课

目录 进程池(process pool) 第一步: 创建并初始化processpool 第二步:主进程对子进程派发任务 补充: 第三步: 子进程执行完退出进程池 回收子进程 进程池的实现 Channel.hpp ProcessPool.hpp Task.hpp main.cc makefile 匿名管道的应用: 进程池 进程池(process po…...

Docker技术全景解析

一、Docker是什么 1.1 定义 Docker是一种容器化技术平台&#xff0c;它通过操作系统级别的虚拟化&#xff0c;将应用程序及其依赖打包成标准化的可移植单元&#xff08;容器&#xff09;。这种技术实现了&#xff1a; 环境一致性&#xff1a;消除“在我机器上能跑”的问题进…...

23种设计模式-状态(State)设计模式

状态设计模式 &#x1f6a9;什么是状态设计模式&#xff1f;&#x1f6a9;状态设计模式的特点&#x1f6a9;状态设计模式的结构&#x1f6a9;状态设计模式的优缺点&#x1f6a9;状态设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是状态设计模式…...

【计算机网络运输层详解】

文章目录 一、前言二、运输层的功能1. 端到端通信2. 复用与分用3. 差错检测4. 流量控制5. 拥塞控制 三、运输层协议&#xff1a;TCP 和 UDP1. TCP&#xff1a;面向连接的可靠传输协议2. UDP&#xff1a;无连接的传输协议 四、端口号与进程通信1. 端口号分类2. 端口通信模型 五、…...

C# 多标签浏览器 谷歌内核Csharp

采用框架 &#xff1a;FBrowserCEF3lib 视频演示&#xff1a;点我直达 成品下载&#xff1a; https://wwms.lanzouo.com/iYOd42rl8vje...

分布式锁实战:Redis与Redisson的深度解析

一、分布式锁的必要性 在分布式系统中&#xff0c;当多个节点需要对共享资源进行读写操作时&#xff0c;传统的本地锁&#xff08;如Java的synchronized或ReentrantLock&#xff09;无法跨节点生效。此时&#xff0c;必须引入分布式锁来保证操作的原子性和一致性。分布式锁需满…...

【Centos7搭建Zabbix4.x监控HCL模拟网络设备:zabbix-server搭建及监控基础05

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 5.zabbix监控HCL模拟网络设备 在保证zabbix-server与HCL网络相通的情况下进行如下操作。 5.1创建主机群 配置-主机群-创建主机群 图 19 取名&#xff0c;添加。 图 20 5.2 创建监控…...

如何在 Windows 上安装并使用 Postman?

Postman 是一个功能强大的API测试工具&#xff0c;它可以帮助程序员更轻松地测试和调试 API。在本文中&#xff0c;我们将讨论如何在 Windows 上安装和使用 Postman。 Windows 如何安装和使用 Postman 教程&#xff1f;...

Zabbix监控K8s集群

虽然 Prometheus 被认为是 监控的Kubernetes最合适的工具 &#xff0c;但其配置复杂、存储成本高以及告警管理繁琐等问题&#xff0c;使得一些传统运维团队更倾向于使用 Zabbix 这样的成熟监控方案。Zabbix 凭借其强大的数据采集、灵活的告警机制和直观的图形化界面&#xff0c…...

基于硅基流动平台API构建定制化AI服务的实践指南

在人工智能技术快速迭代的今天&#xff0c;硅基流动平台&#xff08;SiliconFlow&#xff09;凭借其高效的计算资源调度能力和开放的API接口&#xff0c;成为开发者快速实现AI服务落地的利器。本文将深入探讨如何通过硅基流动平台的API构建一个轻量级AI服务接口&#xff0c;并提…...

自动驾驶系统的车辆动力学建模:自行车模型与汽车模型的对比分析

在自动驾驶系统的车辆动力学建模中,自行车模型(Bicycle Model)和更复杂的汽车模型(如双轨模型或多体动力学模型)各有其适用场景和优缺点。以下是两者的详细对比及选择原因解析: 1. 模型定义与核心差异 特性自行车模型复杂汽车模型(如双轨模型)简化假设将四轮车辆简化为…...

element-ui messageBox 组件源码分享

messageBox 弹框组件源码分享&#xff0c;主要从以下两个方面&#xff1a; 1、messageBox 组件页面结构。 2、messageBox 组件属性。 一、组件页面结构。 二、组件属性。 2.1 title 标题&#xff0c;类型为 string&#xff0c;无默认值。 2.2 message 消息正文内容&#xf…...

洛谷题单1-B2025 输出字符菱形-python-流程图重构

题目描述 用 * 构造一个对角线长 5 5 5 个字符&#xff0c;倾斜放置的菱形。 输入格式 没有输入要求。 输出格式 如样例所示。用 * 构成的菱形。 输入输出样例 #1 输入 #1 输出 #1 **** *********方式-前半区推导&#xff0c;后半区逆序 代码 class Solution:static…...

23中设计模式-迭代器(Iterator)设计模式

迭代器设计模式 &#x1f6a9;什么是迭代器设计模式&#xff1f;&#x1f6a9;迭代器设计模式的特点&#x1f6a9;迭代器设计模式的结构&#x1f6a9;迭代器设计模式的优缺点&#x1f6a9;迭代器设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是…...

第十三章:优化内存管理_《C++性能优化指南》_notes

优化内存管理 一、内存管理基础概念二、自定义分配器三、智能指针优化重点知识代码示例&#xff1a;智能指针性能对比 四、性能优化关键点总结多选题设计题答案与详解多选题答案设计题示例答案&#xff08;第1题&#xff09; 一、内存管理基础概念 重点知识 动态内存分配开销…...

requestAnimationFrame和requestIdleCallback分别是什么,是用在什么场景下

深入解析 requestAnimationFrame 和 requestIdleCallback requestAnimationFrame (rAF) 和 requestIdleCallback (rIC) 都是浏览器提供的 异步调度 API&#xff0c;但它们的执行时机和用途完全不同。 API主要用途何时执行是否保证执行适合场景requestAnimationFrame高优先级 U…...

SAP-ABAP:SAP BW模块架构与实战应用详解

SAP BW模块架构与实战应用详解 目录导航 核心架构分层设计数据建模关键技术典型行业应用场景BW/4HANA革新特性实施路线图常见问题解决方案学习资源推荐一、核心架构分层设计 1. 数据仓库层(Data Warehousing Layer) 组件功能说明典型对象🔄 ETL引擎数据抽取、转换、加载Da…...

准确--配置服务器文件数

某些系统可能在 /etc/security/limits.d/ 目录下有额外配置覆盖全局设置。检查是否存在冲突文件&#xff1a; ls /etc/security/limits.d/如果有文件&#xff08;如 90-nproc.conf 或 90-nofile.conf&#xff09;&#xff0c;需编辑或删除这些文件中的冲突配置。 确保系统启用…...

揭秘大数据 | 12、大数据的五大问题 之 大数据管理与大数据分析

书接上文&#xff0c;老夫讲到规划大数据战略、构建大数据的解决方案与体系架构、解决大数据问题及大数据发展历程中通常会依次涉及到大数据存储、大数据管理、大数据分析、数据科学、大数据应用这五大问题。上篇内容主要围绕的是大数据存储&#xff0c;今天主要聊一下大数据管…...

Java操作RabbitMQ

文章目录 Spring集成RabbitMQ1. AMQP&SpringAMQP2. SpringBoot集成RabbitMQ3. 模型work模型 4.交换机Fanout交换机Direct交换机Topic交换机 5.声明式队列和交换机基于API声明基于注解声明 6.消息转换器 Spring集成RabbitMQ 1. AMQP&SpringAMQP AMQP&#xff08;高级消…...

【MySQL】实战篇—项目需求分析:ER图的绘制与关系模型设计

在软件开发中&#xff0c;数据库是信息系统的核心部分&#xff0c;合理的数据库设计能够显著提高系统的性能和可维护性。 ER图&#xff08;实体-关系图&#xff09;是数据库设计的重要工具&#xff0c;它通过图形化的方式描述了数据实体及其相互关系&#xff0c;帮助开发者和设…...

Apache Shiro 统一化实现多端登录(PC端移动端)

Apache Shiro 是一个强大且易用的Java安全框架&#xff0c;提供了身份验证、授权、密码学和会话管理等功能。它被广泛用于保护各种类型的应用程序&#xff0c;包括Web应用、桌面应用、RESTful服务、移动端应用和大型企业级应用。 需求背景 在当今数字化浪潮的推动下&#xff…...

es新增运算符

?? ( 空值合并运算符) ?. (可选链式运算符) ?? (空值合并赋值操作符) // ?? ( 空值合并运算符)&#xff1a;这个运算符主要是左侧为null和undefined&#xff0c;直接返回右侧值 let result value ?? 默认值;. ??&#xff08;空值合并运算符&#xff09; ✅ 用于…...

数据库三级填空+应用(2)

sysadmin、dbcreator 数据是面向主题的&#xff08;2&#xff09;、集成的、非易失的、随时间不断变化的数据集合&#xff0c; 数据字典 【答案】完整性约束 数据模型成分 33【解析】顺序图主要用于描述系统内对象之间的消息发送和接收序列。 34如果把舍弃的元组也保存在结果关…...

贪心算法经典应用:最优答疑调度策略详解与Python实现

目录 引言&#xff1a;从现实场景到算法设计 一、问题背景与数学建模 1.1 现实场景抽象 1.2 时间线分析 二、贪心策略的数学证明与选择依据 2.1 贪心选择性质 2.2 证明过程 三、算法实现与代码解析 3.1 算法步骤分解 3.2 代码亮点解析 四、测试案例与结果验证 4.1 …...

把手搭建vue前后端管理系统-TAB标签通过pinia来进行管理(二十六)

目标&#xff1a;通过pinia的store来进行组件状态的统一管理&#xff0c;这样大家都可以共用到这个组件的状态信息&#xff0c;就可以实现组件的联动 一、添加侧边栏菜单的点击事件&#xff1a; 1、CommonAside.vue里面添加click的事件 <el-menu-itemv-for"item in …...

Python与数据库

目录 一、数据库 1、数据库的概念 2、数据库的表 3、字段详解 二、SQL数据库语句 1、了解SQL命令 2、CREATE命令 3、INSERT命令 三、数据库和SQL命令 四、数据库的查询与修改 1、SELECT命令 2、UPDATE命令 3、DELETE命令 4、DROP TABLE 5、SQL的注意事项 五、处…...

MyBatis中mapper.xml 的sql映射规则

一、SQL 映射文件核心元素 MyBatis 映射文件的顶级元素&#xff08;按定义顺序&#xff09;&#xff1a; cache&#xff1a;命名空间的缓存配置。cache-ref&#xff1a;引用其他命名空间的缓存。resultMap&#xff1a;自定义结果集映射。sql&#xff1a;可重用的 SQL 片段。i…...

ubuntu22.04安装搜狗输入法保姆教程~

一、添加中文语言支持 1.首先打开设置,找到Language and Region 2.点击Manage Installed Languages 3.点击 Install/Remove Languages... 4.选中Chinese (simplified),点击Apply...

Jenkins 配置python项目和allure

Jenkins新建项目 新建ry-api-auto-test。 添加项目描述&#xff0c;选择gitee令牌。 源码管理&#xff0c;设置仓库地址和凭证。参考我上一篇文章的链接&#xff1a;配置gitee私人令牌和凭证 构建步骤&#xff0c;因为我Jenkins部署在Windows&#xff0c;因此选择batch。…...

keda基于postgresql伸缩dify-api服务

1 概述 dify-api使用postgresql来存储数据&#xff0c;在dify控制台每新建一个聊天机器的聊天框&#xff0c;就会在conversations表里新插入一条记录&#xff0c;并且不断地更新字段updated_at&#xff0c;示例如下&#xff1a; dify# select * from conversations limit 1; …...

蓝桥杯 拼正方形

问题描述 小蓝正在玩拼图游戏。他有&#xff1a; 7385137888721 个 22 的方块10470245 个 11 的方块 他需要从中挑出一些方块来拼出一个正方形。 例如&#xff1a; 用 3 个 22 和 4 个 11 方块可以拼出一个 44 的正方形&#xff1b;用 9 个 22 方块可以拼出一个 66 的正方…...

failed to load steamui.dll”错误:Steam用户的高频崩溃问题解析

当你满心欢喜地双击 Steam 图标&#xff0c;准备进入游戏世界时&#xff0c;屏幕上突然弹出 “failed to load steamui.dll” 的刺眼提示——这是全球数百万 Steam 用户最不愿见到的错误之一。作为 Steam 客户端的核心界面动态链接库文件&#xff0c;steamui.dll 的缺失或损坏会…...

Django之旅:第六节--mysql数据库操作增删改查(二)

前提条件(models.py已经设置好&#xff09;&#xff1a; from django.db import mmodelsclass UserInfo(models.Model):namemodels.CharFIeld(max_length32)passwordmodels.CharFIeld(max_length64)#agemodels.IntegerFIeld()操作数据语法&#xff08;在views.py文件&#xff0…...

6. 使用VUE实现前端页面的分级嵌套

1. 说明 在UI设计中&#xff0c;页面中有些部分的占用空间位置是固定不动&#xff0c;有些部分的区域是根据情况进行动态切换的。比如&#xff0c;一个网页的菜单栏和主题内容展示&#xff0c;往往菜单栏区域的导航按钮占用的空间是固定不动的&#xff0c;当用户点击不同按钮时…...

(UI自动化测试web端)第三篇:元素的常用操作方法_浏览器操作

模拟浏览器的常见操作。 1、最大化浏览器窗口 driver.maximize_window()2、浏览器后退、前进、刷新、关闭、退出 # 调用浏览器的后退 driver.back() # 调用浏览器的前进 driver.forward() # 刷新页面 driver.refresh() # 关闭当前窗口 driver.close() # 退出浏览器 driver.q…...

Ubuntu软件包离线下载安装

1、下载软件包tcpd&#xff0c;并在/var/cache/apt/archives目录中查看。 rooteducoder:~# apt-get install -d tcpd Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed:tcpd …...

第十节 MATLAB逻辑运算

MATLAB逻辑运算都是针对元素的操作&#xff0c;运算结果是特殊的逻辑数组&#xff1b;在逻辑分析时&#xff0c;逻辑&#xff08;真&#xff09;用1表示&#xff0c;逻辑假用0表示&#xff0c;逻辑运算中所有的非零元素作为1处理。 注意&#xff1a; 使用MATLAB逻辑运算时的语…...

初识哈希表

一、题意 给定一个整数数组 nums 和一个目标值 target&#xff0c;要求你在数组中找出和为目标值的那两个整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 示例&#xff1a; 给定 nums [2, 7, …...

Ajax与Axios,以及Apifox的入门使用

Ajax与Axios&#xff0c;以及Apifox的入门使用 作者&#xff1a;blue 时间&#xff1a;2025.3.20 文章目录 Ajax与Axios&#xff0c;以及Apifox的入门使用1.Ajax2.Axios3.Apifox的基本使用内容Path 参数定义语法用途 Query 参数定义语法用途 1.Ajax 概念&#xff1a;Asynchr…...

jmm-java内存模型

java内存模型----底层原理 底层原理 从Java代码到最终执行的CPU指令的流程&#xff1a; 最开始&#xff0c;我们编写的Java代码&#xff0c;是*.java文件在编译&#xff08;javac命令&#xff09;后&#xff0c;从刚才的*.java文件会变出一个新的Java字节码文件&#xff08;…...

机器学习——KNN数据均一化

在KNN&#xff08;K-近邻&#xff09;算法中&#xff0c;数据均一化&#xff08;归一化&#xff09;是预处理的关键步骤&#xff0c;用于消除不同特征量纲差异对距离计算的影响。以下是两种常用的归一化操作及其核心要点&#xff1a; 质押 一 、主要思想 1. 最值归一化&#…...

页面元素内容太长,给元素添加title

一、需求 页面元素内容太长&#xff0c;给元素添加title 二、实现 1、直接使用title属性 <div target"_blank" class"text-overflow" title"叉车司机">叉车司机</div> 2、使用tdesign的Popup 弹出层 <t-popup>触发元素&…...

【Git多分支使用教程】

Git多分支使用教程 Git多分支使用手册目录多分支只拉取一个多分支拉取指定几个步骤 1&#xff1a;克隆第一个分支步骤 2&#xff1a;获取其他分支 常见问题与解决方法1. 错误&#xff1a;origin/分支名 is not a commit2. 分支名称冲突3. --single-branch 限制 总结 Git多分支使…...

【408--复习笔记】数据结构

【408--复习笔记】数据结构 1.绪论数据结构基本概念• 请简述数据结构的定义。• 数据结构中数据、数据元素、数据项、数据对象的区别是什么&#xff1f; 算法相关• 什么是算法&#xff1f;算法的五个重要特性是什么&#xff1f;• 如何理解算法的时间复杂度和空间复杂度&…...

使用 Vite 提升前端开发体验:入门与配置指南

在现代前端开发中&#xff0c;构建工具的选择对开发效率和项目性能有着至关重要的影响。Vite 是一个新兴的前端构建工具&#xff0c;由 Vue.js 的作者尤雨溪开发&#xff0c;旨在通过利用现代浏览器的原生 ES 模块特性&#xff0c;提供更快的开发服务器启动速度和更高效的热更新…...

WPS JS宏编程教程(从基础到进阶)--第二部分:WPS对象模型与核心操作

第二部分&#xff1a;WPS对象模型与核心操作 WPS对象的属性、方法、集合 工作簿对象常用表达方式工作表对象常用表达方式单元格对象常用表达方式 单元格操作实战 单元格复制与重定位单元格偏移与尺寸调整 颜色设置专题 索引颜色与RGB颜色按条件动态设置单元格颜色 第二部分&…...

瑞数信息《BOTS自动化威胁报告》正式发布

在数字化时代&#xff0c;BOTS自动化攻击如同一场无声的风暴&#xff0c;正以前所未有的态势席卷全球网络空间。为了让各行业更好地应对自动化威胁挑战&#xff0c;瑞数信息作为BOTS自动化攻击防护领域的专业厂商&#xff0c;多年来持续输出BOTS自动化威胁报告&#xff0c;为各…...

【NUUO 摄像头】(弱口令登录漏洞)

漏洞简介&#xff1a;NUUO 是NUUO公司的一款小型网络硬盘录像机设备。 NUUO NVRMini2 3.0.8及之前版本中存在后门调试文件。远程攻击者可通过向后门文件handle_site_config.php发送特定的请求利用该漏洞执行任意命令。 1.Fofa搜索语句&#xff1a; 在Fofa网站&#xff0c;搜索&…...

Android系统的安全问题 - Linux的能力模型(Capability)和 SELinux 的区别

Linux 的能力模型&#xff08;Capabilities&#xff09;和 SELinux 是两种不同的安全机制&#xff0c;虽然它们都用于增强 Linux 系统的安全性&#xff0c;但它们的实现方式和目标有所不同。 1. Linux Capabilities&#xff08;能力模型&#xff09; 作用&#xff1a;传统的 …...