进程控制(详解)
上篇文章介绍了进程的相关概念,形如进程的内核数据结构task_struct 、进程是如何被操作系统管理的、进程的查看、进程标识符、进程状态、进程优先级、已经环境变量和进程地址空间等知识点;
本篇文章接着上篇文章继续对进程的控制进行展开,主要包括进程的创建fork,进程的退出和终止、写时拷贝、进程等待(防止僵尸进程的产生使得内存泄漏),进程替换的相关知识!
文章目录
- 进程创建
- fork()的使用场景
- fork()调用失败的原因
- 子进程的数据和代码默认是与父进程共享的
- 创建子进程的操作系统需要干什么
- 父子进程是具有独立性的
- 父子进程既然共享代码和数据如何实现独立性
- 写时拷贝详解
- 进程终止
- 进程退出的场景有哪几种?
- 进程退出的方式
- exit()和_exit()的区别
- 如何获取一个进程的退出码或者退出信号
- 方法一:通过位运算来获取
- 方法二:通过宏来获取
- 进程等待
- 进程等待的用处是什么?
- 进程等待的方式
- wait()函数
- waitpid()函数
- 阻塞等待
- 非阻塞等待
- 进程替换
- 为什么要有程序替换呢?
- 原理是什么?
- 六种程序替换函数
- execl()
- execlp
- execle
- execv()
- execvp
- execvpe
- execve
- exec系列函数用法总结:
进程创建
进程的创建在上篇文章中也有介绍过,进程创建的方式有两种,一种是我们将一个程序跑起来它就会变成一个进程,还有一种就是通过fork()函数创建子进程,主要的创建方式就是通过fork函数,所以我们再来回顾一下fork()函数吧.
fork()函数是一个系统调用接口
//fork()
pid_t fork(void);
返回值: pid_t 类型(实际上是无符号整数) 如果创建子进程成功,返回新创建的子进程的pid(大于0的)给它的父进程,返回0给它自己,如果创建失败就返回-1
注意:fork()成功创建了子进程后就会有父子两个进程,那么也就是说会有两个执行流,fork()会返回两次,分别对父进程和创建出来的子进程进行返回,给父进程返回子进程的pid,因为父进程和子进程的关系是一对多的,所以父进程需要去唯一标识子进程,而进程的pid是天然的标识一个进程的标志,所以fork()返回给父进程的是新创建出来的子进程的pid!而子进程他自己是被创建的时候就知道了自己的pid和其父进程的pid的,所以它不需要fork()函数对他返回任何值,所以fork()就默认给它返回0意思意思一下。上面是创建成功的情况,如果创建失败就会返回-1给当前进程!!!

fork()的使用场景
- 一个进程希望将自己分身,可以一个人做多份工作,那么一个进程就可以通过创建子进程的方式来实现这个目的,可以将自己要干的事分担给子进程,让子进程去帮自己完成。
- 一个进程需要执行别的可执行程序,就可以通过创建子进程的方式,让子进程通过程序替换去帮自己完成程序的执行,我们使用的shell就是这样的,我们执行命令(命令也是可执行程序)的时候,bash就会创建子进程,然后通过程序替换去执行可执行程序。
fork()调用失败的原因
原因非常简单,类比你的手机下来太多东西,容量不够了就不能在下载东西了!
所以fork()创建子进程失败的原因无非就是操作系统中存在太多的进程,内存不够了。
子进程的数据和代码默认是与父进程共享的
我们学习语言的时候了解过继承,子类会继承父类的成员变量,这个理念在进程中同样被使用!
一个进程如果通过fork()函数创建子进程成功,那么它的子进程就会以它的父进程为模板,拷贝它的代码和数据。
创建子进程的操作系统需要干什么
fork()是系统调用,那么就必须要由操作系统来完成子进程的创建工作,那么os会做什么事情呢?
-
根据上篇文章的知识,进程是被操作系统管理起来的,一个进程就是一个task_struct结构体,该结构体包括所有的进程的属性,比如进程的pid、进程的代码对应的地址,数据对应的地址,进程的退出状态,退出信号,进程地址空间等等;
-
操作系统用task_struct 结构体 将进程描述好,再对这些结构体管理,实现对进程的管理工作;
-
知道了上面这些,那么我们就很容易猜到 创建一个进程操作系统就肯定会先创建一个新的task_struct 结构体,该结构体就是那个新新创建的子进程,创建好结构体还没完,还需要对其进行初始化,根据继承的理念,子进程会默认继承父进程的代码和数据,那么操作系统就会把父进程的task_struct中的代码和数据的地址拷贝给子进程;
父子进程是具有独立性的
进程之间是具有独立性的,即使是父子进程也是如此,各个进程之间都是独立运行的!
父子进程既然共享代码和数据如何实现独立性
既然子进程创建出来后是和父进程共享的代码和数据,那么子进程对继承自父进程的数据或代码进行修改,岂不是会对父进程造成影响吗?那怎么还说进程是具有独立性的呢?
- 子进程是和父进程共享的代码和数据没错,进程间具有独立也没有错,错的是子进程修改和父进程共享的数据和代码是不可能会影响到父进程的!因为操作系统考虑到了这个问题,并且让父子进程之间具有写时拷贝的机制,使得在父子一方对共享的资源进行修改是就会将修改的资源分离使得父子各有一份,从而实现进程的独立性!!!
下面具体介绍写时拷贝~
写时拷贝详解
未发生写时拷贝:
未发生写时拷贝的时候,父子是共享这数据和代码的。 它们通过各自的页表将相同的虚拟地址映射到相同的物理地址。

发生写时拷贝后:
当子进程对父子共享的数据或者代码进行修改时,因为进程之间要有独立性,操作不可能直接让子进程将共享的数据给改掉,那样会直接影响到父进程!
所以操作系统会在子进程对父子共享的代码或者数据进行修改的时候,会开辟出一块新的物理空间,将要被修改的代码或者数据拷贝一份之后,让父子中先对共享资源修改的一方去修改新拷贝出来的数据,再让先修改共享资源的一方的页表去重新映射新开辟出来的物理空间实现父子进程的资源分离,互不影响!这就是写时拷贝的基本原理~ (当有一方要对共享资源修改时,为其开要修改的资源开辟新空间,再对该空间的值进行修改,使得二者都有对应的资源,但是被修改的资源不是同一块物理空间了!)

注:写时拷贝的相关操作是由操作系统的内存管理模块完成的!
为什么要有写时拷贝?直接在创建子进程的时候就为其数据和代码开辟新的空间,将其和父进程的数据和代码分离开不好么?
- 1.父子进程的数据,子进程不一定全用,即使使用,也不一定全都会写入(修改)----------存在空间浪费
- 2.最理想的情况是,只有会被父子修改的数据,才会进行分离拷贝,不会修改修改的共享即可 ------理论可以技术角度上无法实现,父子对数据的修改是不可提前预测的
- 3.如果fork的时候就无脑的将父进程的数据拷贝给子进程,就会增加fork的成本(内存和时间层面上)
所以既然写时拷贝存在就有它存在的原因,存在即合理!
写时拷贝是解决上述问题的较为合理的方法,所以才会被采用。写时拷贝是一种演示拷贝的策略,只有当你会对数据进行修改的时候才会给你开辟新的空间,将数据分离,当你不修改的时候,就不会给你新开辟空间,这样省下来的空间就可以被其他进程使用了!体现了os良好的内存管理方案
进程终止
进程退出的场景有哪几种?
- 第一种:代码运行完毕,结果正确
- 第二种:代码运行完毕,结果不正确
- 第三种:代码都没执行完,发生了异常,操作系统直接终止进程
进程退出的方式
- 第一种:通过main函数返回
- 第二种:通过调用exit()函数或系统调用_exit()退出进程
- 第三种:给进程发信号,将进程终止(kill)
上面提到了exit()和_exit(),它们的功能都是让进程退出,两者之间有什么区别呢?
exit()和_exit()的区别
exit()是封装_exit()的函数, _exit()是系统调用。exit() 最终也还是会去调用 _exit() , exit()在 _exit()的基础上增加了新的功能,就是:
- 执行用户通过atexit或on_exit定义的清理函数
- 关闭所有打开的流,所有的缓存数据都会被写入(刷新)

如何获取一个进程的退出码或者退出信号
-
exit(int status)和 _exit(int status)中的参数status就是进程的退出状态码
-
status只有低16位才有价值,它的0-7位是存储着进程的退出信号,8-15位是存的进程的退出码
-
进程正常终止时的退出信号是为0的,退出码为进程设置的退出码
-
进程被信号所终止时,退出码为0,退出信号为进程所收到的信号

方法一:通过位运算来获取
//获取退出码
status>>8&0xFF
//获取退出信号
status&0x7F
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{pid_t id=fork();if(id==0){//childint n=10;while(n--){printf("i am child! i am running pid:%d ppid:%d\n",getpid(),getppid());sleep(1);}exit(110);}else if(id>0){sleep(10);int status=0;waitpid(id,&status,0);if(id>0){sleep(3);printf("等待子进程成功\n");printf("子进程退出码:%d 退出信号:%d 子进程pid:%d \n",status>>8&0xFF,status&0x7f,id);//位运算获取退出码和退出信号的方式}printf("父进程退出!\n");}else {printf("fork error!\n");}return 0;
}
运行结果:

方法二:通过宏来获取
操作系统提供对应的宏来协助我们获取对应的退出信息
| 宏 | 说明 |
|---|---|
| WIFEXITED(int status) | 子进程正常终止则返回真,可以通过WEXITSTATUS(int status)获取子进程退出码 |
| WIFSIGNALED(int status) | 子进程异常终止返回真,若为真可通过WTERMSIG(int status)获取子进程的终止信号 |
| WIFSTOPPED(int status) | 子进程若为暂停状态返回真 |
| WIFCONTINUED(int status) | 子进程被暂停后将其继续的状态,返回真 |
| WEXITSTATUS(int status) | 获取子进程退出码 status的次低8位 |
| WTERMSIG(int status) | 获取子进程终止信号 stauts的低7位 |
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{pid_t id=fork();if(id==0){while(1){printf("i am child pid:%d \n",getpid());sleep(1);//exit(110);}}else {int status=0;int ret=waitpid(id,&status,0);//阻塞式等待子进程if(ret>0){// if(WIFEXITED(status)||WIFSIGNALED(status))if(WIFEXITED(status)){printf("子进程退出! 退出码:%d\n",WEXITSTATUS(status));}if(WIFSIGNALED(status)){printf("子进程退出!退出信号:%d\n",WTERMSIG(status));}}}return 0;
}

进程等待
进程等待的用处是什么?
我们知道子进程退出时如果父进程未读取其相关的退出信息那么该子进程就会变成僵尸进程,僵尸进程会有内存泄漏浪费系统资源,且操作系统无法回收,就算是kill 也不能将它怎么样,因为它已经僵尸了,kill可以杀死在运行的进程,但是它做不到杀死一个已经死去的进程!
- 所以进程等待就是防止产生僵尸进程的处理方式。通过让父进程等待子进程退出,然后再读取它的退出信息,那么子进程就不再僵尸,会变成终止状态,随时等待被系统回收资源!
- 创建子进程一般都是让子进程去完成父进程给它分配的任务,那么父进程就需要知道子进程最终完成的如何,所以父进程有必要等待子进程退出,读取它的退出状态!
进程等待的方式
wait()函数
pid_t wait(int *stauts)wait会等待任意一个子进程
参数:
status是输出型参数,可以通过status获取退出子进程的退出状态(退出码或终止信号)
返回值:
成功返回对应子进程pid,失败返回-1
waitpid()函数
pid_t waitpid(pid_t pid,int* status,int options)waitpid相对wait的可选性更多
参数:
pid : 为-1时,代表着等待任意一个子进程;大于0时,代表等待指定pid的子进程
status:输出型参数,可以通过它获取子进程的退出状态(退出码或终止信号)
options:等待方式,当options为0 时代表父进程阻塞式的等待子进程退出;当options为WNHANG时代表着非阻塞等待,当waitpid返回值为0时,说明子进程还未退出,父进程不会一直在那等待,而是会去干别的事,父进程会以轮询的方式来获取子进程是否退出。
返回值:等待成功返回等待的子进程的pid 失败返回-1
阻塞等待
笼统的理解
所谓的阻塞式等待就是将waitpid中的参数options设置为0,那么父进程就会一直停留在waitpid()这条语句这里,什么也不干就是干等着子进程退出,之后再往下执行后续代码。
系统的理解
父进程阻塞式等待子进程就是当子进程未退出时,操作系统会将父进程的PCB(task_sttuct)放到子进程的等待队列当中,根据前面的进程状态知识可以知道,一个进程等待着某种资源就绪的状态叫做阻塞状态,子进程在等待着父进程退出就是父进程等待着资源就绪,只要子进程不退出,那么父进程就会一直再其等待队列中,直到子进程退出,操作系统才会将父进程继续放回运行队列往下运行后续代码!!!

非阻塞等待
设置非阻塞等待的方式就是将waitpid()中的options设置为WNOHANG即可,那么父进程就会去询问子进程是否退出,如果退出了就返回子进程的pid,未退出返回0,出错返回-1;
通过这种返回就可以让父进程去以轮询的方式去询问子进程是否退出,如果退出就将其回收,否则父进程就可以去干其他事情,而不是一直在原地阻塞着硬等着子进程退出,非阻塞等待的方式可以解放父进程的时间!!!
进程替换
为什么要有程序替换呢?
子进程被创建出来是共享着父进程的代码的,并且会从fork()之后的代码处开始往后执行,那么执行的是和父进程一样的代码,这是没有什么意义的! 我们通常是创建子进程去让子进程去完成其他的工作,比如让子进程去执行其他的可执行程序,那么这里就需要用到进程的替换。
原理是什么?
进程替换的原理就是当进程调用exec系列的进程替换函数后,当前进程的用户空间的代码和数据就会全部被新的程序所替换,接下来就会执行的是新的程序的代码!
注意:进程替换只是将一个进程的用户空间代码和数据用新的程序的代码及数据来替换,整个过程中是没有创建新的进程的,原进程的pid是不变的,变的只有代码和数据!

六种程序替换函数

execl()
int execl(const char *path, const char *arg, ...);函数名中的l代表list,指代传执行程序的方式是按列表的方式传参的
参数列表
path:代表着要执行的程序的绝对路径
arg:执行该程序的方式,这里的arg是一个可变参数列表。(执行指令方式的多个字符串都可以被arg接收),但是传给arg的最后一个字符串必须是NULL
例如:执行ls 命令时 我们敲的是 ls -a -l
那么让ls去替换子进程时,首先path 就是传的ls的绝对路径(/usr/bin/ls),剩下的就是我们的执行方式 ls -a -l 那么arg就得是“ls" “-a” “-l”,当然最后得串一个空代表执行命令结束了,所以传给arg的是"ls",“-a”,“-l”,NULL
执行结果:子进程执行了ls(ls是一个命令 ,也是一个程序!)
execlp
int execlp(const char *file, const char *arg, ...);解释
函数名中的p代表着PATH的意思,带p的替换函数就会自动去搜索环境变量PATH;
所以在带p的替换函数中执行某个程序的时候就可以不用传某个程序的绝对路径,只需传其程序名即可,程序替换函数会自己去环境变量中去找这个程序。
参数列表
第一个就是替换的程序路径(不用写全),第二个就是可变参数列表,接收的是执行的方式,同execl.
execle
int execle(const char *path, const char *arg,..., char * const envp[]);解释
函数名带l,说明传参方式是列表;
函数名中的e代表着environment的意思,也就是环境变量了。execle函数可以自己组装环境变量。
execv()
int execv(const char *path, char *const argv[]);解释
path代表着执行的程序的绝对路径;
argv代表着执行替换程序的方式,用数组的方式传参。
execvp
解释
execvp和execlp只相差了一个字母,一个是l,一个是v,l代表list(列表),v代表vecor(数组)
也就是带l的执行程序的方式是以列表的方式传递的,带v的则以数组的方式传递!
execvpe
解释
类比execle和execlp,带v可知execvp的程序的执行方式以数组形式传递,带p可知其会自己搜索环境变量PATH,带e可知该函数可以自己组装环境变量。
execve
上面的六个函数都是语言封装的execve函数 execve是系统调用
注意:
- exec系列的函数的参数args,是接收的程序执行的方式,其必须以NULL结尾!
exec系列函数用法总结:
| 函数名 | args(执行方式)的传参形式 | 是否带路径(PATH) | 是否使用当前环境变量 |
|---|---|---|---|
| execl | (list)列表 | 否 | 是 |
| execlp | 列表 | 是 | 是 |
| execle | 列表 | 否 | 自己组装环境变量 |
| execv | (vector)数组 | 否 | 是 |
| execvp | 数组 | 是 | 是 |
| execvpe | 数组 | 是 | 自己组装环境变量 |
| execve | 数组 | 否 | 自己组装环境变量 |
相关文章:
进程控制(详解)
进程控制上篇文章介绍了进程的相关概念,形如进程的内核数据结构task_struct 、进程是如何被操作系统管理的、进程的查看、进程标识符、进程状态、进程优先级、已经环境变量和进程地址空间等知识点; 本篇文章接着上篇文章继续对进程的控制进行展开&#x…...
瓜子大王稳住基本盘,洽洽食品做对了什么?
2月24日,洽洽食品披露2022年业绩快报,公司预计实现营收总收入68.82亿元,同比增长14.98%, 实现归母净利润9.77 亿元,同比增长5.21%,业绩基本符合市场预期。来源:洽洽食品2022年度业绩快报2022年,瓜子大王洽洽…...
【音视频安卓开发 (十一)】jni基础
要使用jni开发需要包含jni.h头文件JNIEXPORT JNI : 是一个关键字,不能少(编译能通过),标记为该方法可以被外部调用jstring : 代表java中的stringJNICALL: 也是一个关键字,可以少的jni callJNIENV : 这是c和java相互调用…...
通过FRP搭建内网穿透,实现域名访问局域网本机
1我的目标:实现通过域名访问局域网tomcat服务,域名访问方便本地微信调试2思路:(1)用服务器搭建内网穿透利用FRP实现穿透,frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、…...
Pytorch 代码复现终极指南【收藏】
修改自:https://zhuanlan.zhihu.com/p/532511514我在刚接触pytorch的时候搜到了这个大佬的文章,当时最后天坑部分没有看的太明白,直到今天我也遇到的相同的问题,特来做一点点补充,方便大家理解。上述大佬文章的简版内容…...
iOS 后台运行
背景:app有在后台运行的需求 常用的后台常驻实现方法 1.Audio(音乐播放软件) 应用在后台播放无声的音频文件,只要播放不断,后台可一直活着,苹果审核人员如果发现,会被拒,有可能会…...
软设下午题第一大题--数据流图(做题)
软设下午第一大题一、数据流图(Data Flow Diagram,简称DFD)1、基本图形元素元素(1)外部实体(External Agent)(2)数据存储(Data Store)(3ÿ…...
springboot内嵌Tomcat 安全漏洞修复
漏洞扫描提示的是tomcat-embed-core[CVE-2020-1938],解决方式是升级tomcat的版本。 该漏洞影响的版本: Apache Tomcat 9.x < 9.0.31 Apache Tomcat 8.x < 8.5.51 Apache Tomcat 7.x < 7.0.100 Apache Tomcat 6.x 其余的安全漏洞也可以通过…...
Android OTA 相关工具(三) A/B 系统之 bootctl 工具
文章目录1. bootctl 的编译2. bootctl 的帮助信息3. bootctl 的用法1. hal-info2. get-number-slots3. get-current-slot4. mark-boot-successful5. set-active-boot-slot6. set-slot-as-unbootable7. is-slot-bootable8. is-slot-marked-successful9. get-suffix10. set-snaps…...
【Flink】org.apache.flink.table.api.ValidationException: SQL validation failed
遇到问题如下 Exception in thread "main" org.apache.flink.table.api.ValidationException: SQL validation failed. From line 1, column 15 to line 1, column 17: Object aaa not found at org.apache.flink.table.planner.calcite.FlinkPlannerImpl.orgat org.…...
宏基因组鉴定病毒流程中需要的生物信息工具
谷禾健康 许多流行病的爆发都是病毒引起的,面对新的传染性基因组出现的最佳策略是及时识别,以便于在感染开始时立即实施相应措施。 目前可用的诊断测试仅限于检测新的病理因子。适用于同时检测存在的任何病原体的高通量方法可能比使用基于当前方法的大量…...
Doris入门篇-分区分桶实验
简介 测试分区分桶效果。 分区的基本操作 添加分区 ALTER TABLE v2x_olap_database.government_car ADD PARTITION p20221203 VALUES LESS THAN ("2022-12-04");动态分区表不能添加分区,需要转为手动分区表。 查看分区 show partitions from <表…...
Spring-Xml配置
一、Spring 简介 1.简介 文档下载地址:Index of /spring-framework/docs 1.简介 Spring framework 是 Spring 基础框架 学习Spring 家族产品 Spring framework SpringBoot SpringCloud Spring 能用来做什么 开发 WEB 项目 微服务 分布式系统 Spring framew…...
设计模式-工作线程 创建多少线程池合适
1、定义 让有限的工作线程(Worker Thread)来轮流异步处理无限多的任务。也可以将其归类为分工模式,它的典型实现就是线程池,也体现了经典设计模式中的享元模式(重用对象)。 例如,海底捞的服务员(线程),轮流…...
【算法基础】深度优先搜索(DFS) 广度优先搜索(BFS)
一、DFS & BFS 1. 深度优先搜索DFS 深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。 2. 广度优先搜索BFS 广度优先搜索较之深度优先搜索之不同在于,深度…...
【分布式】ProtocolBuffer平滑升级原则
原文链接:https://blog.csdn.net/nash_cyk/article/details/99549719 关于Protocol Buffer优势这里就不详细介绍了,如便于不同开发语言的交互通信,便于服务器上线的平滑升级等。 但Protocol Buffer的Message协议升级是需要注意一些细节&…...
第四阶段17-关于Redis中的list类型,缓存预热,关于Mybatis中的`#{}`和`${}`这2种格式的占位符
关于Redis中的list类型 Redis中的list是一种先进后出、后进先出的栈结构的数据。 在使用Redis时,应该将list想像为以上图例中翻转了90度的样子,例如: 在Redis中的list数据,不仅可以从左侧压入,也可以选择从右侧压入…...
stringstream用法
stringstream是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的iostream、fstream有类似的操作方式。包含在头文件sstream中(#include <sstream>)。 实例: 1、C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类…...
2022年下半年系统集成项目管理工程师综合知识真题及答案解析
2022年下半年系统集成项目管理工程师综合知识真题及答案解析 1、()不属于“提升云计算自主创新能力”的工作内容。A.加强云计算相关基础研究、应用研究、技术研发、市场培育和产业政策密衔接与统筹协调B.引导大型云计算中心优先在能源充足、气候适宜、自然灾害较少的地区部…...
【洛谷 P2089】烤鸡(搜索)
烤鸡 题目背景 猪猪 Hanke 得到了一只鸡。 题目描述 猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 101010 种配料(芥末、孜然等)…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...







