进程概念(二)
目录
- 进程优先级
- 基本概念
- 查看系统进程
- PRI and NI
- PRI vs NI
- 修改进程优先级的命令
- renice修改优先级进程
- 其他概念
- 环境变量
- 基本概念
- 查看环境变量方法
- 常见环境变量
- PATH
- HOME
- SHELL
- 查看环境变量
- 环境变量相关的命令
- 环境变量特征
- 命令行参数
- main函数中的俩个参数 argc argv
- main函数的第三个参数env——全局性验证
- 环境变量的组织方式
- 内建命令
- 程序地址空间回顾
- fork变量问题
- 进程地址空间
- fork变量问题原因
- 进程地址空间本质
- 为什么要有进程地址空间
进程优先级
系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
查看系统进程
在linux或者unix系统中,使用ps al
查看命令则会类似输出以下几个内容。
我们很容易注意到其中的几个重要信息,有下:
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
UID
其中,在Linux中,系统是通过编号来识别文件,用户等信息的,如上图,1001即是用户的编号。
PRI and NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
- 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
- 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
- 所以,调整进程优先级,在Linux下,就是调整进程nice值
- nice其取值范围是-20至19,一共40个级别
PRI vs NI
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
- 可以理解nice值是进程优先级的修正修正数据
修改进程优先级的命令
用top命令更改已存在进程的nice来更改进程优先级。
- top
- 进入top后按“r”–>输入进程PID–>输入nice值。
当前myproc进程的优先级
查看myproc进程指令
ps al|head -1&&ps al|grep myproc|grep -v grep
使用top命令进入查看进程,再输入r,然后输入要修改进程的PID
最后输入要调整的nice值
注意:我们这里输入的值是100。
最后查看修改后的进程优先级。
nice值确实修改了,对应的PRI值也对应变化了,但nice值却不是我们输入的100,所以可以看出,nice值的修改确实是有范围要求的。其范围为:[20, -19]。
- 而且每次调整NI值,都会从原本的PRI值开始加减NI值
- 如:当前的PRI为30,现在将NI调整为19,那么新的PRI=(旧PRI值)+NI值=20+19=39;而不是30+19=49。
- 旧PRI为最初的PRI值,当前版本下为20。
- 由于版本不同,大家的PRI值有可能不一样,但是NI的调整范围是一样的。
- NI有调整范围是因为Linux还是奉行不相信用户的原则,不能让用户过渡调整优先级,因为当操作系统运行起来后,还有许多系统内部的进程,如果我们可以随意将我们自己创建出来的进程的优先级设置先于系统的进程,我们的进程可能就会霸占原来属于系统进程的资源,这时候就容易会造成进程饥饿问题
renice修改优先级进程
我们也可以使用renice对进程优先级调整。
用法:renice nice值 进程PID
注意:调整进程优先级时,将NI值调为负值需要使用sudo命令提升权限
其他概念
- 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
- 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
- 这里对基于时间片轮转的进程切换简要描述。
当需要运行多个进程时,如一边打游戏一边听歌;CPU在一个时间点只能运行一个进程,所以基于时间片轮换切换进程的方法,当要将一个进程切换为另一个进程时,需要先将当前进程在CPU的上下文信息(也就是需要知道当前进程运行到哪了,以便下次再切换到该进程时得以继续从上次运行的位置开始运行;这也是为什么觉得是多个进程一起运行的假象)保存到PCB对象中,以便下次切换到该进程时将上下文恢复到CPU中。
环境变量
基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
查看环境变量方法
echo $NAME //NAME:你的环境变量名称
加上$才能输出变量的内容,否则就是它的名字。
常见环境变量
PATH
PATH : 指定命令的搜索路径
我们曾在指令介绍一文中讲过指令的本质就是一个个的可执行程序,只不过其在对应的系统路径中,所以不需要.来执行。
- 查看PATH环境变量:发现路径间用:分隔,以上就是我们输入指令后,PATH环境变量会帮助我们找到其可执行程序所在路径。
所以我们如果想让我们自己的可执行程序按照指令的方法执行(不用.来执行)有以下两种方法:
- 将我们的可执行程序加到PATH其中一个路径中;
如“:/usr/bin
- 将我们的可执行程序的所处路径加到PATH中。
修改PATH的方法:PATH=$PATH:添加的路径;该修改方法是覆盖式的,所以把原本的路径也加上,不然本来的系统指令就用不了了。
如果不小心改错了也不用担心,重新登陆即可。
HOME
HOME: 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
不同用户的家目录是不同的,该信息保存在HOME这个环境变量中。
普通用户:
超级用户:
SHELL
SHELL : 当前Shell,它的值通常是/bin/bash。
我们平时所敲的指令都是通过命令行解释器SHELL(可理解为媒婆)向操作系统发送指令的,但在Linux当中有许多种命令行解释器(例如bash、sh(王姓媒婆,陈姓媒婆)),我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类。
查看环境变量
使用env
查看全部环境变量
可以看到有众多的环境变量,包括刚才介绍的PATH,HOME,SHELL。
除此之外还有
环境变量名 | 内容 |
---|---|
HOSTNAME | 主机名 |
HISTSIZE | 记录历史命令的条数 |
SSH_TTY | 当前终端文件 |
USER | 当前用户 |
PWD | 当前所处路径 |
SSH_TTY :向指定终端文件输出
Linux下一切皆文件,SSH_TTY就是对应终端文件
PWD与OLDPWD
这两个环境变量记录当前路径和上一路径;有了PWD,我们的指令pwd就是依赖它实现的,而cd -
这一返回上一路径指令就是依靠OLDPWD完成的。
系统调用接口——getenv
获取指定的环境变量,并将该环境变量返回。
USER
USER该环境变量记录用户是谁。
以下测试:让不同用户跑同一份代码,看看获取的USER是谁。
#include<stdio.h>
#include<stdlib.h>int main()
{printf("who am i:%s\n",getenv("USER"));return 0;
}
可以看到不同用户跑一份代码其结果不一样。这就是环境变量USER起的作用。
环境变量相关的命令
- echo: 显示某个环境变量值
前面已经进行过介绍了
-
export: 设置一个新的环境变量
name=value这种形式只能定义本地变量,如若要新增一个环境变量需要在前面加export;
myproc中使用getenv查找环境变量my_value。 -
env: 显示所有环境变量
-
unset: 清除环境变量
-
set: 显示本地定义的shell变量和环境变量
一般搭配管道|和grep使用
环境变量特征
有了以上例子,我们再回顾,什么是环境变量这一问题:
环境变量是系统提供的一组name=value形式的变量,不同的用户有对应的环境变量,通常具有全局性。
- 全局性可以理解为可以被子进程继承
除环境变量外还可以定义本地变量。
与本次登录有关的变量,只在本次登录内有效。
可以看到本地变量确实不能被getenv函数找到,仅在当前命令行有效,不能被子进程继承,没有全局属性。
那么怎么证明全局变量具有全局性——即可以被子进程继承呢?
命令行参数
在验证环境变量具有全局性前,我们再了解一个知识点——命令行参数。
main函数中的俩个参数 argc argv
我们平时写的代码都是从main函数开始对吧
int mian()
{//codereturn 0;
}
但你知道main函数是可以带参的吗?如以下代码:
int main(int argc, char* argv[])
{ int i=0; for(;i<argc;i++) { printf("argv[i]->%s\n",argv[i]); }return 0;
}
- argc: 记录了argv中的数据个数
- argv: 保存了命令行参数
我们都知道,是函数就可以传参,main函数也不例外,而我们在命令行输入的指令本质上就是在向main函数传参,而char*argv[]本质是一个字符指针数组,叫做命令行参数表;该表就是将在命令行输入的指令当作字符一样存放起来;argc:用来记录了argv中的数据个数。
- 命令行参数表最后一位为NULL
但这就完了吗?这也和环境变量扯不上关系啊!
main函数的第三个参数env——全局性验证
实际上,main函数除了argc和argv两个参数,还有第三个参数,char*env[],这就是环境变量表,它和命令行参数表是一样的。
代码如下:
int main(int argc, char* argv[],char* env[])
{int i=0;for(;env[i];i++){ printf("env[%d]->%s\n",i,env[i]);}return 0;
}
打印环境变量表发现:这不就是我们使用env指令查看的环境变量嘛!!!
于是我们再次阐述几个概念:
- 一个程序加载到内存后,最终变为一个进程;
- 我们所运行的每一个进程都是bash的子进程;
所以,我们运行的进程都是bash的子进程,bash本身启动的时候,会从操作系统的配置文件中读取环境变量,当执行一个指令时,该指令就会继承从父进程中交给我的环境变量。也就是说环境变量具有全局性!!!
实际上每一份代码运行时都需要将上述的命令行参数表,环境变量表传给main函数。
在windows中同样也存在在这种情况。
除了以命令行参数的方式获取环境变量,还可以通过第三方变量environ获取。
#include <stdio.h>
int main(int argc, char* argv[])
{extern char** environ;int i = 0;for (; environ[i]; i++) {printf("%s\n", environ[i]);}return 0;
}
- libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明
环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
内建命令
上面已经证明了环境变量具有全局性,可以被子进程继承;我们输入的指令都是bash的子进程,所以可以继承父进程传过来的环境变量。
但是本地变量是不具有全局性的,但是我们观察一下下面的现象。
不是说本地变量不具有全局性,指令又是bash的子进程吗?为什么echo还能打印本地变量my_value的值呢?
实际上,指令都是bash的子进程这句话并不是完全正确的,指令实际上可以分为两种。
- 常规指令
通过创建子进程完成
- 内建命令
bash不创建子进程,而是由自己亲自执行,类似bash调用自己写的或者系统提供的函数实现。类似echo,cd这样的指令就越是内建命令,不通过创建子进程完成。
利用系统调用接口——chdir自己写一个类似cd的内建命令
chdir:将调用进程的当前工作目录更改为path中指定的目录
模拟cd指令的实现:
利用命令行参数和chdir这一系统调用完成切换路径的工作。
int main(int argc, char* argv[], char* env[])
{if (argc == 2){printf("change begin\n");sleep(20);chdir(argv[1]);printf("change done\n");sleep(10);printf("exit\n");}else{printf("err\n");}return 0;
}
我们用myproc这个进程当作bash,为更好观察更换当前路径这一现象,我们在更换路径前后都休眠一段时间,此时在另一个窗口监视myproc这个进程,在根目录下的系统文件/proc中查看该进程相关信息,cwd为该进程的工作路径,也就是我们的监视目标。当myproc显示切换完成时,可以看到myproc这个进程的cwd确实切换到我们输入的要切换到的路径了。
所以cd指令完全可以由bash自己调用系统函数或者自己写的函数实现。不需要创建子进程。
程序地址空间回顾
以C/C++视角的内存区域划分。
再细致划分一下就是这样的
通过以下代码可以验证以一下
int g_val_1;
int g_val_2 = 100;int main()
{printf("code addr: %p\n", main);const char *str = "hello CSDN";printf("read only string addr: %p\n", str);printf("init global value addr: %p\n", &g_val_2);printf("uninit global value addr: %p\n", &g_val_1);char *mem = (char*)malloc(100);char *mem1 = (char*)malloc(100);char *mem2 = (char*)malloc(100);printf("heap addr: %p\n", mem);printf("heap addr: %p\n", mem1);printf("heap addr: %p\n", mem2);printf("stack addr: %p\n", &str);printf("stack addr: %p\n", &mem);static int a = 0;int b;int c;printf("a = stack addr: %p\n", &a);printf("stack addr: %p\n", &b);printf("stack addr: %p\n", &c);//char *str = "hello bit";//*str = 'H';return 0;
}
运行发现确实如此
- 全局数据中,未初始化的数据区域在初始化数据之上。
fork变量问题
在上一篇介绍fork时我们还遗留了一个问题:
现在我们就可以对这个问题进行解释了,用以下代码更直观看出这个问题
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int main()
{int g_val = 100;if (fork() > 0) {//parent while (1){printf("I am father;g_val:%d g_val_addr:%p\n", g_val, &g_val);sleep(1);}}else {//child int num = 3;while (num--){if (num == 1){printf("#############################\n");g_val = 200;printf("child changed g_val to %d\n", g_val);printf("#############################\n");}printf("I am child:g_val:%d ,g_val_addr:%p\n", g_val, &g_val);}}
}
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
- 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量。
- 但地址值是一样的,说明,该地址绝对不是物理地址!
- 在Linux地址下,这种地址叫做 虚拟地址
- 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理
OS必须负责将 虚拟地址 转化成 物理地址!!!
进程地址空间
从上文得出可知,之前说‘程序的地址空间’是不准确的,准确的应该说成进程地址空间,那该如何理解呢?看图
在学习C/C++时我们都以为那张内存分布图是内存,实际并不是,它实际上也是一个内核数据结构对象,叫mm_struct,也称进程地址空间。
进程地址空间:
将各类数据按照其种类有序存放,存放的是虚拟地址,并不是存放数据代码的真实地址。
页表:
是操作系统中用于存储虚拟内存到物理内存映射的数据结构;负责将虚拟地址转化为真实的物理地址,进而找到数据代码。
之前介绍进程时,我们将进程定义为:内核数据结构对象(task_struct)+数据代码,这时提到的内核数据结构对象是不完整的,现在来看,这里的内核数据对象就不止task_struct一个内核数据结构对象了。而是task_struct + mm_struct (进程地址空间)+ 页表。
fork变量问题原因
所以现在以操作系统的视角看待进程是这样的:
由task_struct,mm_struct,页表组成的内核数据结构 + 数据代码;task_struct有指向mm_struct的指针,mm_struct包含了指向进程页表的指针,该指针为虚拟地址,并不是真实的地址,而页表则是将这个虚拟地址转化为真实的存放数据代码的物理地址,以便CPU可以访问物理内存。
这种设计使得Linux内核可以独立地管理进程的状态和内存资源,从而支持多任务和多用户操作系统的核心功能
注意:每一个进程都会有自己独立的内核数据结构对象(即每个进程都会有一套task_struct,mm_struct,页表)。
所以这时我们就能解释清楚为什么同一个地址会有两个值的问题了:
该地址是虚拟地址,并不是真实存放数据的物理内存的地址;父子进程都会有自己一套独立的内核数据结构对象,但是子进程的内核数据结构对象是拷贝父进程的,所以他们的内容是一样的,所以父子进程会有相同进程地址空间(mm_struct),所以地址是一样的,此时父子进程所指向的数据代码也还是一样的;但是当子进程对父进程的某一个数据进行修改时,就会引发写时拷贝,开辟一块新的空间,这块空间属于子进程;再通过页表将虚拟地址转化,于是就看到了同一个地址,不同值的情况。
进程地址空间本质
所谓进程地址空间,本质是一个描述进程可视范围的大小,这个可视范围指的地址总线的大小,即在C/C++内存分布中所显示的4GB大小,也就是可映射到的内存大小。
这个4GB是怎么来的呢?
读写数据时,CPU和内存之间有⼤量的数据交互的,所以,两者必须也⽤线连起来,这些线一共有三组,我们现在只关注地址总线。
地址总线:
我们可以简单理解,32位机器有32根地址总线,每根线只有两态,表⽰0,1【电脉冲有⽆】,那么⼀根线,就能表⽰2种含义,2根线就能表⽰4种含义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传⼊CPU内寄存器。
而2^32*byte=4GB。
进程地址空间本质
在C/C++层面我们将程序地址空间当作存放数据的内存实际上是不对的,准确的应该说成进程地址空间。
在操作系统的角度来看:进程地址空间本质上是内存中的一种内核数据结构,在Linux当中进程地址空间具体由结构体mm_struct实现。面对大量且不同种类的数据,mm_struct如何进行管理呢?这就得想起管理的六字真言了——先描述,再管理。
进程地址空间就类似于一把尺子,尺子的刻度由0x00000000到0xffffffff,尺子按照刻度被划分为各个区域,例如代码区、堆区、栈区等。而在结构体mm_struct当中,便记录了各个边界刻度,例如代码区的开始刻度与结束刻度,如下图所示:
为什么要有进程地址空间
为什么要有进程地址空间和页表这样的结构呢?让数据直接映射到真实的物理地址上不行吗?
一:让所有进程以统一的视角看待内存
计算机硬件资源是有限的,内存更是如此;但进程却可以有很多,当不同进程向内存申请空间时,进程地址空间可以将这些数据按他们的类型在对应内存类型区域(栈,堆等)生成一个虚拟内存地址,再将该数据随意保存到真实的物理内存中,在页表中将虚拟地址与真实地址建立映射关系,日后通过页表就能进行数据的查找读写。
这样一来,方便了对数据的管理,而且也不需要知道内存中哪里还有空间,做到让所有进程以统一的视角看待内存。
二:增加转化过程,可以对寻址请求做审查,可以保护数据
我们一直说在常量区的数据只能读不能写,这都是从语言的角度上理解的。那么请问:该数据是如何写入的?
char* str = "hello CSDN";//不合法的,有的编译器会直接报错*str = "HELLO csdn";
从系统角度理解:
实际上,物理内存是不会进行请求审查的,物理内存上的的数据是任意读写的;但页表上还有一个标识位来标识这个数据是可读写还是可写,可读的;当想要访问数据时,页表的标识位会先对你的读写请求进行审查,如果没有对应权限,会直接拒绝该请求,达到保护数据的请求。
三:将进程管理,内存管理进行解耦合,确保内存管理模块不会影响进程管理模块
操作系统不仅仅只有进程管理模块,还有内存管理模块;一款好的软件要求做到低耦合的效果,不能因为一个模块出了毛病导致整个软件崩溃。进程地址空间和页表能够将进程管理模块和内存管理模块很好的分离,做到进程管理模块不需要知道一个程序是怎么加载到内存的,它只需要做好自己对进程的管理即可,内存管理模块也是如此。
再补充一点:
当进程在CPU运行时,CPU的cr3寄存器保存的是当前进程对应页表的地址;并且页表的地址属于task_struct的上下文信息。进行进程切换时仍是切换task_struct就可以了,因为进程地址空间也是由task_struct指向的,页表地址也会保存在task_struct中。
相关文章:
进程概念(二)
目录 进程优先级基本概念查看系统进程PRI and NIPRI vs NI修改进程优先级的命令renice修改优先级进程其他概念 环境变量基本概念查看环境变量方法常见环境变量PATHHOMESHELL 查看环境变量环境变量相关的命令 环境变量特征命令行参数main函数中的俩个参数 argc argvmain函数的第…...
java程序100道01—20
1.用循环的嵌套,输出输出如下图形 * * * * * * * * * * * * * * * * * * * * * * * * * package Exercises.One_Hundred; public class Demo01 {public static void main(String[] args) {for(int i1;i<5;i){for(int j1;j<2*i-1;j){Sys…...
让GNSSRTK不再难【第二天-第7部分2】
状态更新计算过程: 计算卡尔曼增益: 根据预测的误差协方差矩阵 P k − P_k^- Pk− 和观测噪声协方差矩阵 R R R 计算卡尔曼增益 K k K_k Kk: K k P k − H T ( H P k − H T R ) − 1 K_k P_k^- H^T (H P_k^- H^T R)^{-1} KkPk…...
计算引擎:Flink核心概念
Apache Flink 是一个流处理框架,擅长处理实时数据流和批处理任务。Flink 提供了强大的功能来处理和分析大量数据。以下是 Flink 的核心概念: 1. DataStream 和 DataSet API DataStream API: 用于处理无界数据流,即不断生成和流动的数据。例如,传感器数据、日志等。DataSet…...
技术前沿 |【大模型InstructBLIP进行指令微调】
大模型InstructBLIP进行指令微调 一、引言二、InstructBLIP模型介绍三、指令微调训练通用视觉语言模型的应用潜力四、InstructBLIP的指令微调训练步骤五、实验结果与讨论六、结论与展望 一、引言 随着人工智能技术的快速发展,视觉语言模型(Vision-Langu…...
CSS-布局-flex
CSS3 新增了弹性盒子模型( Flexible Box 或 FlexBox ),是一种新的用于在 HTML 页面实现布局的方式。使得 HTML 页面适应不同尺寸的屏幕和不同的设备时,元素是可预测地运行。 基本概念 容器:使用 display:flex 或 display:inline-flex 声明的…...
「C系列」C 数组
文章目录 一、C 数组1. 声明数组2. 初始化数组3. 访问数组元素4. 数组越界5. 多维数组 二、C 操作数组的方法有哪些三、C 数组-应用场景1. 存储固定数量的数据2. 实现算法(如排序)3. 处理数据集合 四、相关链接 一、C 数组 在C语言中,数组是…...
Python框架scrapy有什么天赋异禀
Scrapy框架与一般的爬虫代码之间有几个显著的区别,这些差异主要体现在设计模式、代码结构、执行效率以及可扩展性等方面。下面是一些关键的不同点: 结构化与模块化: Scrapy:提供了高度结构化的框架,包括定义好的Spider…...
【ROS2大白话】四、ROS2非常简单的传参方式
系列文章目录 【ROS2大白话】一、ROS2 humble及cartorgrapher安装 【ROS2大白话】二、turtlebot3安装 【ROS2大白话】三、给turtlebot3安装realsense深度相机 【ROS2大白话】四、ROS2非常简单的传参方式 文章目录 系列文章目录前言一、launch文件传参的demo1. 编写launch.py文…...
浅谈mysql 的批量delete 和 使用in条件批量删除问题
在考虑这两个DELETE语句的性能时,我们需要考虑数据库如何执行这些查询以及它们背后可能涉及的索引和数据结构。 1.执行多个单独的DELETE语句: DELETE FROM a WHERE b 1 AND c 1; ... DELETE FROM a WHERE b 1000 AND c 1000; 这种方法的优点是每…...
【Spring Boot】过滤敏感词的两种实现
文章目录 项目场景前置知识前缀树 实现方式解决方案一:读取敏感词文件生成前缀树构建敏感词过滤器1. 导入敏感词文件 src/main/resources/sensitive_words.txt2. 构建敏感词过滤器 SensitiveFilter3. 测试与使用 解决方案二:使用第三方插件 houbb/sensit…...
在 Zustand 中管理状态能使用类(Class)吗
在 Zustand 中,通常不推荐使用类(Class)来管理状态,因为 Zustand 的设计理念是基于函数式编程和 React Hooks 的。然而,仍然可以在 Zustand 中间接地使用类,但这并不是 Zustand 的典型用法。 如果确实想要…...
MoreTable 方法selectWithFun,count 使用实例
ORM Bee, example for MoreTable methods:selectWithFun,count ORM Bee时, MoreTable 方法selectWithFun,count 使用实例 package org.teasoft.exam.bee.osql;import org.teasoft.bee.osql.BeeException; import org.teasoft.bee.osql.FunctionType; import org.teasoft.be…...
【SpringBoot】在Spring中使用自定义条件类在Java声明Bean时实现条件注入
在Spring框架中,通过实现org.springframework.context.annotation.Condition接口并重写matches()方法,可以根据自定义条件来控制Bean的注入。这种机制非常灵活,可以帮助开发人员根据环境或配置来有选择地启用或禁用某些Bean。本文将详细介绍如…...
网卡聚合链路配置
创建名为mybond0的绑定,使用示例如下: # nmcli con add type bond con-name mybond0 ifname mybond0 mode active-backup添加从属接口,使用示例如下: # nmcli con add type bond-slave ifname enp3s0 master mybond0要添加其他从…...
PlantSimulation导入cad图作为背景
PlantSimulation导入cad图作为背景 首先要整理cad文件,正常的工艺规划总图中存在较多杂乱文件,这些信息是不需要的,如果直接导入,会非常卡。 1、打开cad软件,使用layon命令打开所有的隐藏图层,删除不需要…...
【大模型】个人对大模型选择的见解
选择大模型产品时,需要考虑多个因素,包括但不限于以下几点: 需求匹配度:首先,要明确你的需求是什么。不同的大模型产品可能在功能、性能、应用场景等方面有所侧重。例如,有的模型擅长自然语言处理ÿ…...
java的反射和python的鸭子类型
Java的反射(Reflection)和Python的鸭子类型(Duck Typing)感觉相似但又说不出具体的细节,本文借助kimi试图给出总结。 相似之处: 动态性:Java的反射允许程序在运行时查询、创建和修改类和对象的…...
爬虫工具yt-dlp
yt-dlp是youtube-dlp的一个fork,youtube-dlp曾经也较为活跃,但后来被众多网站屏蔽,于是大家转而在其基础上开发yt-dlp。yt-dlp的github项目地址为:GitHub - yt-dlp/yt-dlp: A feature-rich command-line audio/video downloaderA …...
【代码随想录训练营】【Day 50】【动态规划-9】| Leetcode 198, 213, 337
【代码随想录训练营】【Day 50】【动态规划-9】【需二刷】| Leetcode 198, 213, 337 需强化知识点 需二刷,打家劫舍系列 题目 198. 打家劫舍 class Solution:def rob(self, nums: List[int]) -> int:if len(nums) 1:return nums[0]dp [0] * (len(nums))dp…...
源码讲解kafka 如何使用零拷贝技术(zero-copy)
前言 kafka 作为一个高吞吐量的分布式消息系统,广泛应用与实时应用场景中。为了实现高效的数据传输,kafka使用了零拷贝技术(zero-copy)显著提高了性能。本文将详细讲解 Kafka 如何利用零拷贝技术优化数据传输。 什么是零拷贝 零拷贝技术目的是减少数据传输的效率。在传统…...
Ubuntu20.04配置qwen0.5B记录
环境简介 Ubuntu20.04、 NVIDIA-SMI 545.29.06、 Cuda 11.4、 python3.10、 pytorch1.11.0 开始搭建 python环境设置 创建虚拟环境 conda create --name qewn python3.10预安装modelscope和transformers pip install modelscope pip install transformers安装pytorch co…...
java自学阶段二:JavaWeb开发--day80(项目实战2之苍穹外卖)
《项目案例—黑马苍穹外卖》 目录: 学习目标项目介绍前端环境搭建(前期直接导入老师的项目,后期自己敲)后端环境搭建(导入初始项目,新建仓库使用git管理项目,新建数据库,修改登录功能ÿ…...
HPUX系统Oracle RAC如何添加ASM磁盘
前言 HPUX简介 HP-UX (Hewlett-Packard Unix) 是惠普公司开发的类 Unix 操作系统。自 1980 年代问世以来,HP-UX 在技术和功能上不断发展,适应了多种硬件平台和企业计算需求。以下是 HP-UX 的发展历史概述: 1980 年代:起源与早期…...
Jmeter 压力测测试的简单入门
下载安装 官方网站:Apache JMeter - Download Apache JMeter 下载完成解压即可。 配置 1. 找到 bin 目录下的 ApacheJMeter.jar 包,直接打开 如果向图片这样不能直接打开,就在此路径运行 CMD,然后输入下面的命令即可启动。 ja…...
N叉树的层序遍历-力扣
本题同样是二叉树的层序遍历的扩展,只不过二叉树每个节点的子节点只有左右节点,而N叉树的子节点是一个数组,层序遍历到一个节点时,需要将这个节点的子节点数组的每个节点都入队。 代码如下: /* // Definition for a N…...
解决阿里云的端口添加安全组仍然无法扫描到
发现用线上的网站扫不到这个端口,这个端口关了,但是没有更详细信息了 我用nmap扫了一下我的这个端口,发现主机是活跃的,但是有防火墙,我们列出云服务器上面的这个防火墙list,发现确实没有5566端口 参考&a…...
【因果推断python】26_双重稳健估计1
目录 不要把所有的鸡蛋放在一个篮子里 双重稳健估计 关键思想 不要把所有的鸡蛋放在一个篮子里 我们已经学会了如何使用线性回归和倾向得分加权来估计 。但是我们应该在什么时候使用哪一个呢?在不明确的情况下,请同时使用两者!双重稳健估计…...
C语言 图形化界面方式连接MySQL【C/C++】【图形化界面组件分享】
博客主页:花果山~程序猿-CSDN博客 文章分栏:MySQL之旅_花果山~程序猿的博客-CSDN博客 关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长! 目录 一.配置开发环境 二…...
Unity DOTS技术(十五) 物理系统
要解决性能的瓶颈问题,在DOTS中我们将不再使用Unity自带的物理组件. 下面来分享一下在DOTS中当如何使用物理插件. 一.导入插件 在使用DOTS系创建的实体我们会发现,游戏物体无法受物理系统影响进行运动.于是我们需要添加物理系统插件. 1.打开Package Manager > 搜索插件Uni…...
wordpress 命令执行时间/营销策划公司介绍
文/黑水泛金波 问题一、套头是不是都很差? 答:不是。肯定不是。 事实上,厂家在决定用什么样的头来作为“套头”、跟机身组成“套机”一起销售的时候,的确就已经先考虑好了、用户最可能需要的镜头会是哪一个。这往往跟机身的“气质…...
高端网站制作费用/网站软件免费下载
docker-compose.yml version: "2" services:eid-service:# 指定容器名称container_name: xxx-service# 重启机制restart: always# hub地址,image版本image: hub.xxx.cn/xxx-service/xxx-service:latestvolumes:# 本地jar包路径- /opt/service/1.5/xxx-se…...
秦皇岛网站制作专家教您简单建站/苏州百度 seo
你好,我是小马总,96年互联网创业者 今天探讨一个创业路上最重要的一个点,合伙生意到底能不能做? 能创业的人都是有魄力的 ,既然你能刷到这篇文章,说明你不是在创业的路上就是有了创业的想法,给…...
如何修改网站域名/品牌策划与推广
你会给电动车充电吗?说到电动车充电,可能大家都不以为然,不就是一个充电吗?有什么不会的,一头接电源,一头连电池,这有什么不会的。你有没有发现,自认为会给电动车充电的你࿰…...
茂名建设企业网站/app接入广告变现
Android系统为设置界面的UI提供了一系列的接口,设置界面的部分和Activity是分离的,会有一个PreferenceScreen的对象是根目录,在其中会包含CheckBoxPreference EditTextPreference ListPreference PreferenceCategory RingtonePreference相关的…...
做网站发广告/简述网络营销的特点及功能
在ASP.NET 中使用 Unity Application Block – 示例(提供代码下载) 下面的示例演示在ASP.NET Web Application 中使用 Unity 依赖注入容器。下载ASP.NetWeb Application源码!!! 具体步骤如下: 1. 创建IUnit…...