Linux: 进程间通信
目录
一 前言
二 进程间通信目的
三 进程间通信方法
四 管道通信
1. 进程如何通信
2.管道概念
2.1匿名管道
2.2 匿名管道对多个进程的控制
2.3 命名管道
2.4 命名管道原理
一 前言
在我们学习进程的时候,我们知道正是因为程序地址空间的存在,所以进程之间具有独立性,他们互不影响,但是在我们的实际应用中,进程之间总会有需要通信(交流获取对方数据)。
二 进程间通信目的
-
数据传输:一个进程需要将它的数据发给另一个进程。
-
资源共享:多个进程之间共享同样的资源。
-
通知事件:一个进程需要向另一个进程或一组进程发送消息,通知它(它们)发生了某种事件。
-
进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态的转变。比如我们在程序调试代码的时候就是一个进程完全控制了另一个进程。
三 进程间通信方法
Linux为用户提供了三种进程间通信的方法
- pipe管道通信:比如我们在进程一篇中用到的命令 ‘|’ 就是使用管道,该命令是和其他命令组合起来使用的。如搭配 grep 文本內容过滤工具使用。" ps -ajx | grep lrk "该命令就是将ps进程执行的数据通过管道传输给了 grep,才能筛选出指定的內容。管道一般是用于本地进程之间的数据传输。其又分为 匿名管道 和 命名管道
- POSIX进程通信:是一套进程通信的标准,可以为操作系统提供进程通信的接口。
- System V进程通信:也是一套进程通信的标准,可以为操作系统提供进程通信的接口。
四 管道通信
1. 进程如何通信
我们知道进程的程序地址空间决定了进程之间的独立性,这就给进程之间的通信造成了极大的困难,但是我们思考一下通信的本质是什么,即就是一个进程向另一个进程传递数据,而我们的进程始终是在操作系统内运行着的,那么进程是不是可以通过操作系统中的资源进行通信呢?
就像一个进程向同一份文件中写入数据,另一个进程去该文件中读取。这样的情况下,我们就通过访问同一个资源达成了数据传输的目的。即进程之间的通信的前提其实是不同的进程需要先能够看到、能够获取到同一份资源(文件、内存等)。该资源的种类其实就决定了进程通信的方式。
2.管道概念
管道是Unix中最古老的进程间通信的方式了。管道顾名思义,就是类比于生活中的管道才得名的。只不过生活中的管道输送的是谁、天然气等现实生活中的资源,而系统中的管道则是传输数据的,是一个进程链接到另一个进程的数据流。
事实上,管道就是一个被打开的文件(内存级文件),但是这个文件很特殊,向这个文件内写入的数据实际上并不会放入磁盘中,管道是在内存中实现的,并由操作系统的内核管理。当一个进程向管道写入数据时,这些数据被存储在内核中的缓冲区;然后,另一个进程可以从同一管道读取这些数据。一旦数据被读取,它们就从缓冲区中移除,符合现实中的管道特征:只传输资源,不存储资源。且需要注意的是管道是单项传输的。示意图 如下:
管道分为两种:匿名管道和命名管道 ,其实就是根据两种管道所打开的方式不同而做的分类。
2.1匿名管道
匿名管道从名字来说,这个管道没有特定的名称,即在创建它的时候,不会指定打开文件的文件名、文件路径等,不会创建实际文件在文件系统中,纯粹存在于内存中,由操作系统内核进行管理。用于进程间通信。由于匿名管道是非明确目标的文件,对于两个毫不相关的进程是无法一起找到这个管道文件的(即两个无关的进程是无法找到公共资源),也就是说只有具有“血缘”关系的进程才能使用匿名管道进行通信。而父子进程共享数据,因此父子进程可以通过创建匿名管道进行通信。
💊下面就图解一下父子进程如何创建匿名管道进行通信
1.首先父进程分别以只读和只写打开管道文件(创建管道文件过程):
2.接着父进程创建子进程,子进程会继承父进程的文件打开方式:
3.接下来父进程关闭读端,子进程关闭它的写端,父进程只负责往管道文件里面写入,子进程读取就行了
这样就创建了一个匿名管道。
🚀:为什么父进程需要以两种方式打开管道文件呢?不能以想要的方式打开管道文件然后子进程再以它想要的方式打开文件不就行了?这种太过于麻烦了,子进程在创建的时候会自动继承父进程的文件打开方式,这时候我们只需要各自关闭一个文件即可。
🎯匿名管道的创建
系统调用函数:pipe()
int pipe(int pipefd[2]),中 pipefd[2],这个数据存放的是什么呢?我们接下来打印一下看看。
运行结果:
- pipe[0]=3:存储的是以只读方式打开管道时获取的fd
- pipe[1]=4:存储的是以只写方式打开管道时获取的fd
🏃接下来我们根据父子进程创建匿名管道进行通信的三个步骤写一个测试:
1.首先父进程分别以只读和只写打开管道文件(创建管道文件过程,通过系统调用函数pipe()---------------------->2.接着父进程创建子进程,子进程会继承父进程的文件打开方式----------->3.接下来父进程关闭读端,子进程关闭它的写端,父进程只负责往管道文件里面写入,子进程读取就行了
#include <iostream>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
using namespace std;
//mypipe.cpp
//父进程进行读取,子进程进入写入
int main()
{// 第一步,创建管道文件,打开读写端int fds[2];int n = pipe(fds);assert(n == 0);// 第二步,创建一个子进程forkpid_t id=fork();assert(id>=0);if(id==0){//子进程进行写入close(fds[0]);//子进程通信代码const char* s="我是子进程,我正在给你发消息";int cnt=0;while(true){cnt++;char buffer[1024];//向指定缓冲区写入snprintf(buffer,sizeof buffer,"child->parent say: %s[%d][%d]\n",s,cnt,getpid());//子进程向管道写入端写入write(fds[1],buffer,strlen(buffer));//将buffer的数据写入管道sleep(5);//每隔1秒写入一次//sleep(50);}//写入完成结束之后,把子进程写入端关闭close(fds[0]);exit(0);}//父进程进行读取close(fds[1]);//父进程通信代码while(true){char buffer[1024];//cout<<"AAAAAAAAAAAAAAAAAAAAAAAAAA"<<endl;ssize_t s=read(fds[0],buffer,sizeof(buffer)-1);//将读取的数据放到buffer中,读取大小为sizeof(buffer)//cout<<"BBBBBBBBBBBBBBBBBBBBBBBBBB"<<endl;if(s>0) buffer[s]=0;cout<<"Get Message"<<buffer<<"| my pid "<<getpid()<<endl;//这样父进程就读到了子进程传输的信息。}//进程等待n=waitpid(id,nullptr,0);assert(n==id);//读取完成结束之后,把父进程读取端关闭close(fds[0]);return 0;
}
运行结果
接下来我们对代码进行一点改动。来探索,子进程是依何种状态来与父进程进行通信的
运行结果
从测试结果可知,当父进程sleep(50)之后向管道写入的时候,子进程会进入阻塞状态一直等待父进程向管道传输数据。
⛳pipe文件具有访问控制机制,必须先写入才能读取。父子进程在对管道文件进行读写操作是阻塞式I\O,即管道文件中必须先有数据,读取端才能去读取,否则调用read时就会发生阻塞;同样,如果管道中被写满了数据,此时再调用write也会发生阻塞,直到管道中有足够的空间来写入。
2.2 匿名管道对多个进程的控制
🍰上面我们看到了只由一个父进程通过管道文件派发任务控制一个子进程的例子,那我们当然也可以通过对多个子进程派发任务来控制多个子进程。此时一个匿名管道就不够用了,我们需要多个匿名管道,既然需要创建多个匿名管道,那么我们就需要让父进程知道不同的子进程对应的不同的管道的写端。即我们需要让父进程知道所要派发任务的子进程的匿名管道的写端。
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cassert>
#include <vector>
#include <string>
#include <sys/wait.h>
#include <sys/types.h>
#include <ctime>#define PROCSS_NUM 5//子进程个数
#define MakeSeed() srand((unsigned long)time(nullptr) ^ getpid() ^ 0x124587 ^ rand() % 1234)//定义随机种子,用来随机选择进程///子进程要完成的任务///
typedef void (*func_t)(); // 函数指针,表示进程任务
void downLoadTask()
{std::cout <<getpid()<< ":下载任务" << std::endl;sleep(1);
}
void ioTask()
{std::cout <<getpid()<< ":IO任务" << std::endl;sleep(1);
}
void flushTask()
{std::cout << getpid()<<":刷新任务" << std::endl;sleep(1);
}
// 加载任务函数:将3个任务加载起来,放到vector中,组成加载任务表
void loadTaskFunc(std::vector<func_t> *out)
{assert(out);out->push_back(downLoadTask);out->push_back(ioTask);out->push_back(flushTask);
}/多进程程序/
// 子进程端点
class subEp
{
public:// 构造函数subEp(pid_t subId, int writeFd): subId_(subId), writeFd_(writeFd){char nameBuffer[1024];snprintf(nameBuffer, sizeof nameBuffer, "process-%d[pid(%d)-fd(%d)]", num++, subId, writeFd);name_ = nameBuffer;}public:static int num;std::string name_; // 子进程名称pid_t subId_; // 子进程的pidint writeFd_; // 子进程写端的文件描述符
};
int subEp::num = 0; // 静态变量初始化要在类外//读取父进程传递给子进程命令码:即读取管道的读端
int recvTask(int readFd)
{int code=0;ssize_t s=read(readFd,&code,sizeof(code));//读取到&code中,大小4个字节if(s==4) return code;//返回读取结果else if(s<=0) return -1;else return 0;
}
// 创建子进程
void createSubProcess(std::vector<subEp> *subs, std::vector<func_t> &funcMap)
{for (int i = 0; i < PROCSS_NUM; i++){// 为每个进程建立对应的管道int fds[2];int n = pipe(fds);assert(n == 0);(void)n;pid_t id = fork();if (id == 0){// 子进程,进行处理任务close(fds[1]); // 子进程进行读取while (true){// 1.获取命令码,如果没有发送,进程阻塞int commandCode=recvTask(fds[0]);//读取过程//父进程如果不写,子进程处于阻塞状态,父进程代码持续执行// 2.完成任务if(commandCode>=0 && commandCode < funcMap.size()) funcMap[commandCode]();//执行对应函数else if(commandCode==-1) break;}exit(0);}//父进程对于代码close(fds[0]); // 父进程关闭对应管道的读端进行写入subEp sub(id, fds[1]);subs->push_back(sub);//走到这里有5个子进程且有对于的pid 和writeFd}
}
// 发送任务
void sendTask(const subEp &process, int taskNum)
{std::cout << "send task num:" << taskNum << "send to-> " << process.name_ << std::endl;int n = write(process.writeFd_, &taskNum, sizeof taskNum);//父进程向子进程写入//write(fd,buffer,sizeof buffer)//将buffer的内容写入fd对应的文件//父进程向那个子进程的writeFd写入了,那个子进程开始读取assert(n == sizeof(int));(void)n;
}void loadBlanceControl(const std::vector<subEp>& subs,const std::vector<func_t> & funcMap, int count)
{// 2. 走到这就是父进程,控制子进程int processnum = subs.size();//子进程个数5个int tasknum = funcMap.size(); // 任务个数bool forever= (count==0 ? true :false);while (true){// 1.选择一个进程--------->std::vector<subEp>--->index------>随机数int subIdx = rand() % processnum; // 一共有多少子进程// 2. 选择一个任务-------->std::vector<func_t>---indexint taskIdx = rand() % tasknum;// 3. 任务发给选择的进程(父进程进行写)sendTask(subs[subIdx], taskIdx);//父进程向管道写入任务几的时候,此时子进程就不是阻塞状态了开始读取sleep(1);if(!forever){count--;if(count==0) break;}}//父进程退出,关闭各个子进程写端for(int i=0;i<processnum;i++) close(subs[i].writeFd_);
}
//回收子进程
void waitProcess(std::vector<subEp> process)
{int processnum=process.size();for(int i=0;i<processnum;i++){waitpid(process[i].subId_,nullptr,0);std::cout<<"wait subprocrss success ..."<<process[i].subId_<<std::endl;}
}int main()
{MakeSeed();//随机种子,用来随机分配任务// 1建立5个子进程并建立和子进程通信的匿名管道std::vector<func_t> funcMap; // 任务表loadTaskFunc(&funcMap);//将任务都放在vector中std::vector<subEp> subs;//子进程,subEp是一个类createSubProcess(&subs, funcMap);//创建子进程,且这个函数会给每个进程分配一个任务// 2. 走到这就是父进程,控制子进程int taskCnt=20;//0:永远进行loadBlanceControl(subs,funcMap,taskCnt);// 3.回收子进程信息。waitProcess(subs);return 0;
}
运行结果
2.3 命名管道
🍉:上述管道应用的一个限制:就是只能在具有共同祖先(具有亲缘关系)的进程间通信。因父子进程共享资源,所以彼此能找到公共资源。 如果我们想在不相关的进程之间交换数据,该怎么做呢?
我们可以使用FIFO文件来做这项工作,它经常被称为命名管道。 命名管道是一种特殊类型的文件
创建命名管道函数mkfifo()
接下来我们写一个例子,来初步理解命名管道
然后我们用系统调用函数mkfifo(),创建一个命名管道
上述-------------------done > named_pipe 向命名管道named_pipe 输入hello linux
> 命令行可以看成一个进程,向named_pipe 输入数据。 cat < 可以看出另外一个不相关的进程 ,通过cat < named_pipe
cat <named_pipe 输出了hello Linux ,我们可以理解为完成了两个不相关的进程通过named_pipe完成了通信。
2.4 命名管道原理
🌔:要想进行进程间的通信,必须让两个进程看到同一份资源,那命名管道是如何做到让两个不同的进程看到同一份资源的?
我们可以让不同的进程打开指定名称(路径+文件名)的同一文件
路径+文件名=唯一性
命名管道是操作系统提供的可以共享的资源,不同的是命名管道是一个特殊的文件,它与普通文件有所不同,命名管道文件的内容不需要刷新到磁盘中,因为它仅需要进行通信即可,不需要耗费时间空间去将内容保存在磁盘中,所以它的文件大小一直是0。
接下来我们写一个测试,让不同的进程通过命名管道进行通信
#include"common.hpp"
//客户端 client.cpp
int main()
{int rfd=open(NAMED_PIPE,O_WRONLY);if(rfd<0) exit(-1);//WRITEchar buffer[1024];while(true){std::cout<<"please say#"<<std::endl;fgets(buffer,sizeof(buffer),stdin);buffer[strlen(buffer)-1]=0;ssize_t n= write(rfd,buffer,strlen(buffer));}close(rfd);return 0;
}
#include "common.hpp"
//服务端 server.cpp
int main()
{//服务端,创建命名管道bool r =createFifo(NAMED_PIPE);assert(r);//通信int rfd=open(NAMED_PIPE,O_RDONLY);//打开文件,以读的方式if(rfd<0) exit(-1);//readchar buffer[1024];while(true){ssize_t s= read(rfd,buffer,sizeof( buffer)-1);if(s>0){buffer[s]=0;std::cout<<"client->server : "<<buffer<<std::endl;}else if(s==0){std::cout<<"client quit"<<std::endl;break;}else{std::cout<<"client error"<<std::endl;}}//移除管道close(rfd);removeFifo(NAMED_PIPE);return 0;
}
server.cpp 和client.cpp通过 共同文件common.cpp进行通信。
#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <fcntl.h>#define NAMED_PIPE "/tmp/mypipe.100" //定义一个命名管道路径
common.cpp
bool createFifo(const std::string& path)
{umask(0);int n=mkfifo(path.c_str(),0600);if(n==0) return true;else{std::cout<<"errno:"<< errno <<"err string:"<< strerror(errno) <<std::endl;return false;}
}void removeFifo(const std::string &path)
{int n= unlink(path.c_str());assert(n==0);(void)n;
}
运行结果如下:
相关文章:
Linux: 进程间通信
目录 一 前言 二 进程间通信目的 三 进程间通信方法 四 管道通信 1. 进程如何通信 2.管道概念 2.1匿名管道 2.2 匿名管道对多个进程的控制 2.3 命名管道 2.4 命名管道原理 一 前言 在我们学习进程的时候,我们知道正是因为程序地址空间的存在ÿ…...
为什么idea显示数据库连接成功,但操作数据库时,两边数据不同步
今日份小bug又叕又来了! 一、原因分析 1. 未提交的事务 - IDEA 中执行了修改操作但未提交事务 - 其他客户端有未提交的修改 2. 连接隔离级别问题 - 不同连接使用了不同的事务隔离级别 - 读未提交(READ UNCOMMITTED)导致看到未提交数据 3. 多客户端同时操作…...
VMware中新建Ubuntu虚拟机系统,并安装Anaconda
详细介绍 Ubuntu18.04版本的安装Anaconda的安装 Ubuntu20.04版本的安装给出其他参考 安装Ubuntu18.04 新建虚拟机 如果不习惯图文形式的,也可参考该up主的环境安装分享,和我如下记录有些不同,但不影响,大部分均一致。 …...
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板 一、揭开 LangChain 的 “灵魂引擎”:Prompt 的核心作用 在 LangChain 构建的智能应用中,Prompt(提示词)堪称驱动大模型的 “神经中枢”。这个承载着任务…...
项目如何安装本地tgz包并配置局部registry
一、判断包来源是否正确 1. 检查url curl <registry_url>2. 查看包是否存在 npm view <package_name> --registry<registry_url>二、局部registry配置步骤: 1. 全局配置 如果你希望对所有项目生效,可以将这行配置添加到全局.npmr…...
unity客户端面试高频2(自用)
标题是我 1.构造函数为什么不能为虚函数?析构函数为什么要虚函数?2.C智能指针3.左值和右值完美转发 4.深拷贝与浅拷贝5.malloc VS new 你们知道吗 1.构造函数为什么不能为虚函数?析构函数为什么要虚函数? 构造函数不能定义为虚函…...
【12】Ajax的原理和解析
一、前言 二、什么是Ajax 三、Ajax的基本原理 3.1 发送请求 3.2 解析内容 3.3 渲染网页 3.4 总结 四、Ajax 分析 五、过滤请求-筛选所有Ajax请求 一、前言 当我们在用 requests 抓取页面的时候,得到的结果可能会和在浏览器中看到的不一样&a…...
深度学习在测距模型中的应用
一、单目视觉测距和双目视觉测距简介 1、单目视觉测距 模型:深度估计(Depth Estimation) 原理:通过深度学习模型(如MonoDepth2、MiDaS)或传统的计算机视觉方法(如单目相机结合物体大小推断&am…...
Python np.vectorize函数介绍
np.vectorize 是 NumPy 提供的一个 用于将标量函数(scalar function)向量化 的工具,使其可以作用于 NumPy 数组,类似于 通用函数(ufunc) 的行为。 1️⃣ np.vectorize 语法 numpy.vectorize(pyfunc, otypes=None, signature=None, excluded=None, cache=False)📌 参数…...
HarmonyOS NEXT状态管理实践
在HarmonyOS NEXT开发中,状态管理是构建高效、响应式应用的核心。本文深入探讨状态管理的最佳实践,结合代码示例与案例分析,帮助开发者掌握这一关键技能。 一、状态管理装饰器的合理使用 HarmonyOS NEXT提供多种状态管理装饰器,…...
广告牌变“高空炸弹“?智能预警终端筑起安全防线!
近年来,随着城市发展步伐加快,广告牌已成为城市形象的重要载体。但与此同时,因设计缺陷、违规搭建、维护缺失等问题导致的广告牌坠落事故频发,给市民生命财产安全带来严重威胁。据不完全统计,我国2000万块户外广告牌中…...
scss预处理器对比css的优点以及基本的使用
本文主要在vue中演示,scss的基本使用。安装命令 npm install sass sass-loader --save-dev 变量 SCSS 支持变量,可将常用的值(如颜色、字体大小、间距等)定义为变量,方便重复使用和统一修改。 <template><…...
Redis 单线程
Redis 读写是否是单线程? 核心数据操作仍然是单线程 Redis 主要采用 单线程执行命令,这是因为: 避免加锁:如果多个线程并发修改数据,就需要加锁,而 Redis 采用单线程保证操作的原子性,无需加…...
Node.js 下载安装及环境配置教程、卸载删除环境配置超详细步骤(附图文讲解!) 从零基础入门到精通,看完这一篇就够了
Node.js 安装 一、进入官网地址下载安装包 Node.js — Download Node.js 选择对应你系统的Node.js版本,这里我选择的是Windows系统、64位 Tips:如果想下载指定版本,点击【以往的版本】,即可选择自己想要的版本下载 二、安装程序…...
第十五章:Python的Pandas库详解及常见用法
在数据分析领域,Python的Pandas库是一个不可或缺的工具。它提供了高效的数据结构和数据分析工具,使得数据处理变得简单而直观。本文将详细介绍Pandas库的基本功能、常见用法,并通过示例代码演示如何使用Pandas进行数据处理。最后,…...
Windows下VSCode的安装
前言 VSCode的安装看起来平平无奇,但也不是轻轻松松的。笔者将最新的Windows下安装VSCode,以及运行最简单的C程序的过程记录下来,供后续的自己和大家参考。 一、官网下载安装包 Visual Studio Code - Code Editing. Redefined 二、安装 直接…...
PgDog:一个PostgreSQL分布式集群中间件
PgDog 是一个实现了 PostgreSQL 分片、连接池以及负载均衡功能的中间。PgDog 使用 Rust 语言编写,支持跨平台(Linux、Mac OS、Windows),具有高性能和高可靠性,可以在不需要修改任何应用程序的前提下实现 PostgreSQL 数…...
基于yolov11的棉花品种分类检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
【算法介绍】 基于YOLOv11的棉花品种分类检测系统是一种高效、准确的农作物品种识别工具。该系统利用YOLOv11深度学习模型,能够实现对棉花主要品种,包括树棉(G. arboreum)、海岛棉(G. barbadense)、草棉&a…...
Web网页内嵌福昕OFD版式办公套件实现在线预览编辑PDF、OFD文档
PDF,即Portable Document Format,用于以一种独立于应用程序、硬件、操作系统的方式共享和查看文档;OFD,即Office Open Document Format for Document,是一种在政府公文和法律文件等领域广泛应用的电子文件格式…...
UE4学习笔记 FPS游戏制作32 主菜单,暂停游戏,显示鼠标指针
文章目录 一主菜单搭建UI显示主菜单时,暂停游戏,显示鼠标绑定按钮 二 打开主菜单 一主菜单 搭建UI 添加一个MainUi的控件 添加一个返回游戏的按钮和一个退出游戏的按钮 修改一下样式,放中间 显示主菜单时,暂停游戏࿰…...
多线程 - 线程安全引入
写一个代码,让主线程创建一个新的线程,由新的线程负责完成一系列的运算(比如:1 2 3 ... 1000),再由主线程负责获取到最终结果。 但打印结果为 result 0,略微思考,明白了要让 t 线…...
Angular项目改端口号
在 Angular 项目中修改开发服务器的端口号(默认是 4200),可以通过以下几种方式实现: 方法 1:通过 ng serve 命令行参数 直接在运行 ng serve 时指定端口号: ng serve --port 4300效果:开发服务…...
论文内可解释性分析
目录 3 TEPM(Text-Enhanced Prototype Module)3.1 为什么要进行文本增强?(动机)3.2 为什么要使用 Concat(Fv, T) 和 Repeat(T) + Fv?3.3 为什么 Q=F_C,K=V=F_R ?(第一层注意力)3.4 为什么要进行两层注意力?3.5 为什么最终结果会更好?**3.6 面试官可能问的挑战性问题*…...
《C++11:通过thread类编写C++多线程程序》
关于多线程的概念与理解,可以先了解Linux下的底层线程。当对底层线程有了一定程度理解以后,再学习语言级别的多线程编程就轻而易举了。 【Linux】多线程 -> 从线程概念到线程控制 【Linux】多线程 -> 线程互斥与死锁 语言级别的…...
@Resource 与 @Autowired:Spring 中的依赖注入注解大比拼
在 Spring 框架中,依赖注入(DI)是核心功能之一,它允许开发者将组件之间的依赖关系交给 Spring 容器管理,从而实现解耦和更灵活的代码结构。Resource 和 Autowired 是两种常用的依赖注入注解,它们虽然功能相…...
大模型学习:从零到一实现一个BERT微调
目录 一、准备阶段 1.导入模块 2.指定使用的是GPU还是CPU 3.加载数据集 二、对数据添加词元和分词 1.根据BERT的预训练,我们要将一个句子的句头添加[CLS]句尾添加[SEP] 2.激活BERT词元分析器 3.填充句子为固定长度 代码解释: 三、数据处理 1.…...
Git和GitCode使用(从Git安装到上传项目一条龙)
第一步 菜鸟教程-Git教程 点击上方链接,完成Git的安装,并了解Git 工作流程,知道Git 工作区、暂存区和版本库的区别 第二步 GitCode官方帮助文档-SSH 公钥管理 点击上方链接,完成SSH公钥设置 第三步(GitCode的官方引…...
NodeJs之http模块
一、概念: 1、协议:双方必须共同遵从的一组约定。 Hypertext Transfer Protocol:HTTP,超文本传输协议 2、请求: ① 请求报文的组成: 请求行请求头空行请求体 ② 请求行: 请求方法URLHTTP版本…...
【深度学习与实战】2.3、线性回归模型与梯度下降法先导案例--最小二乘法(向量形式求解)
为了求解损失函数 对 的导数,并利用最小二乘法向量形式求解 的值 这是线性回归的平方误差损失函数,目标是最小化预测值 与真实值 之间的差距。 损失函数: 考虑多个样本的情况,损失函数为所有样本的平方误差之和&a…...
在word中使用zotero添加参考文献并附带超链接
一、引言 在写大论文时,为了避免文中引用与文末参考文献频繁对照、修改文中引用顺序/引用文献时手动维护参考文献耗易出错,拟在 word 中使用 zotero 插入参考文献,并为每个参考文献附加超链接,实现交互式阅读。 版本:…...
在Linux系统中将html保存为PNG图片
1 前言 之前使用Pyecharts库在Windows系统中生成图表并转换为PNG格式图片(传送门),现将代码放于Linux服务器上运行,结果发现错误,生成html文件之后无法保存图片。 2 原理 基于Selenium库的保存方案,其原…...
presto任务优化参数
presto引擎业内通常用它来做即席查询,它基于内存计算效率确实快,不过它自身的任务优化参数比较杂,不同类型的catalog能用的参数不完全一样,在官网上倒是可以看到相关资料,配置文件中写的见https://prestodb.io/docs/cu…...
uniapp + Axios + 小程序封装网络请求
前言 小程序自带的网络请求使用起来比较麻烦,不便于管理,就需要封装网络请求,减少繁琐步骤,封装最终效果,根据类别将网络请求封装在文件中,使用得时候调用文件名名称加文件中得自定义名称,就可…...
《网络管理》实践环节01:OpenEuler22.03sp4安装zabbix6.2
兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 1 环境 openEuler 22.03 LTSsp4PHP 8.0Apache 2Mysql 8.0zabbix6.2.4 表1-1 Zabbix网络规划(用你们自己的特征网段规划) 主机名 IP 功能 备注 zbx6svr 19…...
4.6js面向对象
js原型继承 JavaScript 的原型链继承是其核心特性之一,理解原型链对于掌握 JavaScript 的面向对象编程至关重要。 1. 原型(Prototype)基础 在 JavaScript 中,每个对象都有一个内部属性 [[Prototype]](可以通过 __p…...
【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft Fabric 服务器搭建,Fabric 模组详细搭建教程
【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft Fabric 服务器搭建,Fabric 模组详细搭建教程 一、 服务器介绍二、安装 JDK 21三、搭建 Minecraft 服务端四、本地测试连接五、如何添加模组(mods)六、添加服务,并设置开…...
SQL SELECT DISTINCT 语句详解:精准去重的艺术
SQL SELECT DISTINCT 语句详解:精准去重的艺术 一、为什么需要数据去重? 在日常数据库操作中,我们经常会遇到这样的场景:查询客户表时发现重复的邮箱地址,统计销售数据时出现冗余的订单记录,分析用户行为…...
从ChatGPT到AutoGPT——AI Agent的范式迁移
一、AI Agent的范式迁移 1. ChatGPT的局限性与Agent化需求 单轮对话的“工具属性” vs. 多轮复杂任务的“自主性” ChatGPT 作为强大的生成式AI,虽然能够进行连贯对话,但本质上仍然是“工具型”AI,依赖用户提供明确的指令,而无法自主规划和执行任务。 人类介入成本过高:提…...
SQL EXISTS 与 NOT EXISTS 运算符
EXISTS 和 NOT EXISTS 是 SQL 中的逻辑运算符,用于检查子查询是否返回任何行。它们通常用在 WHERE 子句中,与子查询一起使用。 EXISTS 运算符 EXISTS 运算符用于检查子查询是否返回至少一行数据。如果子查询返回任何行,EXISTS 返回 TRUE&…...
AGI 的概念、意义与未来展望
随着人工智能技术的飞速发展,我们已经见证了在图像识别、自然语言处理等特定领域取得的巨大突破。然而,这些成就都属于弱人工智能(Narrow AI)的范畴,它们只能在预设的任务范围内高效工作。 人们对于一种拥有更广泛、更…...
基于Java与Go的下一代DDoS防御体系构建实战
引言:混合云时代的攻防对抗新格局 2024年某金融平台遭遇峰值2.3Tbps的IPv6混合攻击,传统WAF方案在新型AI驱动攻击面前全面失效。本文将以Java与Go为技术栈,揭示如何构建具备智能决策能力的防御系统。 一、攻击防御技术矩阵重构 1.1 混合攻击特征识别 攻击类型Java检测方案…...
FPGA调试笔记
XILINX SSTL属性电平报错 错误如下: [DRC BIVRU-1] Bank IO standard Vref utilization: Bank 33 contains ports that use a reference voltage. In order to use such standards in a bank that is not configured to use INTERNAL_VREF, the banks VREF pin mu…...
Axure项目实战:智慧城市APP(七)我的、消息(显示与隐藏交互)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:智慧城市APP 主要内容:我的、消息、活动模块页面 应用场景:消息页设计、我的页面设计以及活动页面设计 案例展示ÿ…...
深度学习——图像余弦相似度
计算机视觉是研究图像的学问,在图像的最终评价时,往往需要用到一些图像相似度的度量指标,因此,在本文中我们将详细地介绍原生和调用第三方库的计算图像余弦相似度的方法。 使用原生numpy实现 import numpy as npdef image_cosin…...
求矩阵某列的和
设计函数sum_column( int A[E1(n)][E2(n)], int j ),E1(n)和E2(n)分别为用宏定义的行数和列数,j为列号。在该函数中,设计指针ptr&A[0][j],通过*ptr及ptrptrE2(n)访问第j列元素,从而求得第j列元素的和。在主函数中定…...
【论文分析】无人机轨迹规划,Fast-Planner:实时避障+全局最优的路径引导优化算法
这篇论文《Robust Real-time UAV Replanning Using Guided Gradient-based Optimization and Topological Paths》由香港科技大学提出,主要针对无人机(UAV)在复杂环境中的实时轨迹重新规划问题,提出了一种结合梯度优化和拓扑路径搜…...
李飞飞、吴佳俊团队新作:FlowMo如何以零卷积、零对抗损失实现ImageNet重构新巅峰
目录 一、摘要 二、引言 三、相关工作 四、方法 基于扩散先前的离散标记化器利用广告 架构 阶段 1A:模式匹配预训练 阶段 1B:模式搜索后训练 采样 第二阶段:潜在生成建模 五、Coovally AI模型训练与应用平台 六、实验 主要结果 …...
AutoDev 2.0 正式发布:智能体 x 开源生态,AI 自动开发新标杆
在我们等待了几个月之后,国内终于有模型(DeepSeek V3-0324)能支持 AutoDev 的能力,也因此是时候发布 AutoDev 2.0 了!在 AutoDev 2.0 中,你可以: 编码智能体 Sketch 进行自动化编程自动化编程的…...
PHP 应用MYSQL 架构SQL 注入跨库查询文件读写权限操作
MYSQL 注入:(目的获取当前 web 权限) 1 、判断常见四个信息(系统,用户,数据库名,版本) 2 、根据四个信息去选择方案 root 用户:先测试读写,后测试获取…...
鸿蒙-全屏播放页面(使用相对布局)---持续更新中
最终实现效果图: 实现步骤 创建FullScreenPlay.ets全品播放页面 并将其修改为启动页面。 全屏播放,屏幕必然横过来,所以要将窗口横过来。 编辑 src/main/ets/entryability/EntryAbility.ets 若写在/EntryAbility.ets中,则所有…...