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

【Linux】操作系统与进程

🦄个人主页:修修修也

🎏所属专栏:Linux

⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位)


目录

📌操作系统

🎏操作系统的概念

🎏设计操作系统的目的

🎏操作系统对进程的管理

🕹️操作系统为什么要对进程进行管理?

🕹️操作系统如何对进程进行管理?

📌进程

🎏进程的概念

🎏进程的描述——PCB(process control block)

🕹️Linux下的PCB——task_struct

🕹️task_struct内容分类

🎏进程管理

🕹️组织进程

🕹️查看进程

🕹️通过系统调用获取进程标示符

🎏创建进程

🕹️fork()函数

🕹️fork()函数的两个返回值

🕹️进一步探究fork()函数

🎏进程状态

🕹️操作系统层面进程的状态

🕹️Linux系统层面进程的状态

🎏进程优先级

🕹️基本概念

🕹️PRI和NI的概念

🕹️查看/修改进程优先级命令

结语


📌操作系统

🎏操作系统的概念

        任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等等)

🎏设计操作系统的目的

  • 与硬件交互,管理所有的软硬件资源
  • 为用户程序(应用程序)提供一个良好(稳定, 高效, 安全)的执行环境

🎏操作系统对进程的管理

🕹️操作系统为什么要对进程进行管理?

        进程是操作系统进行资源分配和调度的基本单元。操作系统通过管理进程来实现对资源的分配和调度。


🕹️操作系统如何对进程进行管理?

        操作系统通过下面两个行为来完成对进程的管理:

  1. 描述进程
  2. 组织进程

        描述进程主要是将进程的各种重要的属性描述出来, 比如将进程id, 父进程id, 进程状态, 进程优先级等属性合为一个结构体来描述一个进程。这就像我们将学生的各种属性, 如姓名, 性别, 学号, 班级, 年龄, 成绩等合为一个结构体来描述一个学生一样。

        组织进程则是通过按照进程的各种属性来将进程组织运行起来。这也很好理解, 比如我们要组织一个班级进行野炊活动, 我们就按照各个同学的特长将同学们分组, 一组去拾柴, 一组去收拾场地, 一组去收集食材, 一组处理食材。这样组织同学们共同完成野炊这个任务, 就类似于操作系统组织进程完成用户的任务一样。

        注意, 操作系统管理的只是进程的属性, 通过对进程属性结构的增删查改来管理进程, 而并非去管理每个进程本身有什么行为。


📌进程

🎏进程的概念

        进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。

        在早期面向进程设计的计算机结构中,进程是程序的基本执行实体, 如正在执行的程序;

        在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体


🎏进程的描述——PCB(process control block)

  • 进程信息被放在一个叫做进程控制块数据结构中,可以理解为进程属性的集合
  • 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct

🕹️Linux下的PCB——task_struct

  • 在Linux中描述进程的结构体叫做task_struct。
  • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息
  • task_struct非常大, 感兴趣的朋友可以看一下它的源码 : task_struct英文源码原文

🕹️task_struct内容分类

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息

🎏进程管理

🕹️组织进程

        Linux内核中, 最基本的组织进程task_struct的方式是采用双向链表组织。

        但实际上Linux内核中组织进程的方式错综复杂, 可能是好几种数据结构互相嵌套在一起


🕹️查看进程

        如下代码,我们先在Linux中创建一个进程(程序):

#include<stdio.h>
#include<unistd.h>
int main()
{    while(1){printf("进程正在运行中...\n");sleep(1);}return 0;
}

        然后用gcc编译运行这个程序:

        可以看到进程正在每隔一秒打印一次提示信息,然后我们在另一个终端使用ps命令查看一下这个进程信息:

ps ajx | head -1 && ps ajx | grep mypro  //查看mypro相关的进程
//或
ps ajx | head -1 ; ps ajx | grep mypro   //查看mypro相关的进程

        还有一种查看进程的方式是通过查看/proc目录来查看进程:

ls /proc  //查看当前系统的所有进程

        然后我们可以通过查看具体的进程目录来查看进程的信息:

ls /proc/4206 -l

        或者也可以通过top命令来查看进程:


🕹️通过系统调用获取进程标示符

  • 进程id(PID)
  • 父进程id(PPID)

        可以通过getpid(),getppid()来获取进程id和父进程id,函数手册如下:

        函数使用示例:

        我们编写一个进程,然后调用getpid()和getppid()函数来获取它的进程id和父进程id,代码如下:

        使用gcc编译运行,再在另一个窗口查询进程相关信息:

        可以看到getpid()和getppid()获取的进程id和父进程id信息是正确的。


🎏创建进程

🕹️fork()函数

        我们前面尝试了在指令级别运行一个进程,即运行我们写的程序; 现在我们来看一下在代码层面如何创建一个进程。

        先来看一下Linux的fork()函数手册:

        我们通过一段代码来观察一下fork()函数调用的现象,代码如下:

        编译运行代码,结果如下:

        可以看到, fork()函数后的代码竟然被打印了两遍! 这是因为我们在调用fork()函数之前程序只有一个执行流,而调用fork()函数之后程序就开始有两个执行流了,所以两个执行流都执行了打印操作,我们的屏幕上才会看到两个打印的结果。


🕹️fork()函数的两个返回值

        我们可以看到fork()函数拥有两个返回值,一个是返回给父进程的子进程id,一个是返回给子进程的0。如果fork()函数创建子进程失败了,就会给父进程返回-1,并适当设置errno报错.

        下面我们测试一下接收fork()函数的返回值,代码如下:

        编译运行,结果如下:

        可以看到, 子进程和父进程分别执行了其对应的不同的代码逻辑,并且我们可以明显发现,这个测试中fork()函数应该是优先执行父进程的,所以父进程的信息先被打印了出来。但实际上父子进程的执行先后是由调度器来决定的, 可能不同系统, 不同进程甚至不同时间测试结果都有可能不一样, 完全取决于调度器如何安排, 是不确定的。

        至此,我们发现fork()函数确实是创建了一个新的进程, 只有两个进程一起运行, 这段代码才可能打印出两个if语句的分支循环结果,否则按照C语言单进程的执行逻辑, 程序一旦进入其中一个死循环就再也不可能出来了, 那么我们将只能看到其中一个死循环在打印。


🕹️进一步探究fork()函数

        关于fork()函数,有几个问题需要解答一下:

1.为什么fork()函数要给子进程返回0,给父进程返回子进程pid?

        我们给父子进程设置不同返回值的目的,就是为了让我们在调用fork()函数之后,可以根据不同的if判断来让父子进程执行不同的代码片段因此返回不同的返回值,是为了区分不同的执行流,使其可以执行不同的代码块。需要注意的是,一般而言,fork()函数之后的代码是父子共享的!

        而具体我们给父进程返回子进程的pid的原因则是为了方便父进程后续对子进程做管理, 因为父进程的子进程可能不止一个,因此需要分别记录下子进程的id方便其后续对子进程的精准管理

2.fork()函数究竟做了什么?

        fork()函数的主要工作大概有下面几个:

  1.         创建子进程PCB
  2.         填充PCB对应的内容
  3.         让子进程和父进程指向同样的代码
  4.         父子进程都有独立的task_struct,可以被CPU调度运行
  5.         ......(fork()函数的主要工作完成之后,后面的代码就是父子共享的了!)
  6.         return id ;    (因为这里的fork()函数的return 语句已经在成功创建子进程后了,这意味着从那之后父子进程就会分别拥有一个return 语句,这样就可以做到父进程返回一个值,子进程返回一个值了)

3.一个函数是如何做到返回两次的?我们该如何理解这一现象?

        如上问fork()函数的工作内容所示,因为一旦子进程创建好后后面的代码就是共享的了,所以return 语句自然也变成父子共享的,所以他们就会通过这个共享的return 语句来得到分别属于自己的返回值。这样也就做到了返回两次值的效果。

4.一个变量怎么会存有不同的内容?如何理解这一现象?

       对父子进程而言,他们的进程代码是共用的,而它们的进程数据则采用写时拷贝的方式, 拷贝出的进程数据互不干扰, 可以分别使用即实际上这个变量已经不是一个变量了,而是父进程的变量和写时拷贝出的子进程变量这两个变量,因此可以存不同的内容

        这样安排的主要原因是进程间相互具有独立性, 进程代码因为不会被进程更改,所以父子共享是没问题的,但进程数据是可能被进程更改的,如果父子进程间可以互相影响数据,那么就很容易导致出错的情况。

        这就好比我们现实生活中父子可以在一栋房子里生活, 不会因为父亲住了房子就坏了,儿子不能住了,也不会因为儿子住了导致房子有什么变化导致父亲不能住了。但是父子间不能共用一个钱包,否则可能父亲刚想给家里买一台空调,就发现钱包的钱已经被孩子拿去买乐高了。这样会互相干扰,就会导致出事。


🎏进程状态

🕹️操作系统层面进程的状态

        进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。在三态模型中,进程状态分为三个基本状态,即运行态,就绪态,阻塞态。在五态模型中,进程分为新建态、终止态,运行态,就绪态,阻塞态。

🌳运行状态

        进程占有处理器正在运行或正处于运行队列中。

🌳阻塞状态

        进程不具备运行条件,正在等待某个事件的完成。

🌳挂起状态

        进程的挂起状态是指计算机系统中,一个进程因为某些原因而暂时不能继续执行,但仍然保持在进程表中,并且有可能在将来恢复执行的状态。


🕹️Linux系统层面进程的状态

        Linux内核中源码定义的进程状态:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

🌳R : 运行状态( running )

  • 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

        但是要注意,我们查看进程时,不能只根据表面来推测判断它处于什么状态,而应该更严谨的去分析进程的行为再做判定。

        比如,我们创建一个程序,代码如下:

        然后我们运行进程,查询该进程的状态:

        可以发现明明左边进程一直在运行,但是右边查询进程属性的结果却显示进程在等待状态。这是因为我们在进程中调用了printf()函数,即调用了硬件设备显示器来向屏幕上打印内容,而当硬件显示器在打印内容时,进程就是处于等待硬件工作的状态的, 并且硬件显示器向屏幕打印的时间相对CPU运行时间来说很慢,两者是数量级的差别,硬件几乎占了99.99%的时间,所以我们在查询进程状态时,大部分时间查到的都是进程在等待打印的时候。

        当我们将while循环中的打印语句删除,再运行,查询进程状态:

        可以看到,进程当前处于R运行状态:

        小tips:

        带+的状态表示是在前台运行的进程,如果我们在运行进程指令后面加一个 & ,那么进程就会在后台运行,状态后面就不会有+号。(杀后台进程用kill -9 [pid]来完成)

🌳S : 睡眠状态( sleeping )

  • 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断(浅度)睡眠(interruptible sleep))。浅度睡眠状态意味着该进程当前是可以相应操作系统的操作的,比如可以直接被操作系统杀死。

🌳D : 磁盘休眠状态( Disk sleep )

  • 有时候也叫不可中断(深度)睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。并且该进程不会响应任何操作系统的请求, 即操作系统无法将其杀死或者是进行其他任何操作。这样做主要是为了防止操作系统将某些重要的正处于等待状态的进程误杀。

🌳T : 停止状态( stopped )

  • 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

         可以通过给进程发kill -18/19 [pid]来使进程恢复运行/暂停.

         T状态和S状态的区别是:两者都可以是为了等待某种资源而暂停,但T状态更为自由一些,它也可以不是因为等某种硬件资源,而是单纯的就是不想进程再运行,所以就可以将进程暂停。

🌳Z : 僵死状态( zombie )

  • 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程就会进入Z状态
  • 处于僵死状态的进程就被成为僵尸进程,其相关资源尤其是task_struct结构体不能被释放,这也就会导致僵尸进程会一直占用内存资源!

        一个进程在退出之后并不是就要立即将自己的所有资源全部释放, 而是操作系统要将该进程的退出信息维持一段时间, 直到该退出进程的相关进程知道了该进程退出的相关信息和原因之后,才会释放该进程的相关信息和资源。从进程退出,到相关进程接收到退出信息之间的这一段状态,就成为进程的僵死状态。

         我们通过一段代码演示一下僵死状态,我们用fork()创建一个子进程,然后让它休眠3秒之后直接退出,同时我们让父进程休眠30秒,这样在子进程退出后由于父进程处于休眠状态就没法立即回收子进程的信息,子进程就会进入僵死状态,代码如下:

        然后我们编译运行程序,调出监控窗口查看进程状态, 监控命令如下:

while :; do ps axj | head -1 && ps axj | grep zombie;sleep 1; echo "----------------------------------------------";done

        查看结果,可以看到子进程确实从第三秒后就变成了僵死状态,名字后面也被标上了<defunct>:

僵尸进程的危害:

  • 无人回收时进程的退出状态必须被维持下去,因为他要告诉和它相关的进程(父进程),你交给我的任务,我完成的怎么样,又或是遇到了怎样的状况。父进程如果一直不读取子进程的退出信息,那子进程就会一直处于Z状态!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,如果Z状态一直不退出,PCB就一直都要维护
  • 如果一个父进程创建了很多子进程,但是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,要在内存的某个位置进行开辟空间,这就会导致内存泄漏!

🌳孤儿进程

        我们刚刚讨论的是子进程比父进程先死亡的情况,但还有一种可能的情况是父进程比子进程先死亡,这种子进程就被成为孤儿进程,该进程会被1号进程(即操作系统)领养,代码如下:

        编译运行,调用监控查看结果:

        所以父进程是1号进程(操作系统)的进程就被称为孤儿进程.操作系统领养孤儿进程的主要目的是为了后续回收孤儿进程的退出信息并将其释放,防止存在内存泄漏问题。

🌳X : 死亡状态( dead )

  • 这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

🎏进程优先级

🕹️基本概念

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能( 但前提是能够客观公平的设置,一般情况下还是遵守调度器的调度,不要擅自修改进程优先级 )。
  • 还可以把进程运行到指定的CPU上, 把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

🕹️PRI和NI的概念

        我们在linux或者unix系统中,用ps –l命令会输出以下几个内容:

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值
  • PRI即进程的优先级,通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
  • NI就是nice值,其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,加入nice值后,PRI变为:PRI(new) = PRI(old) + nice
  • 当nice值为负值时,该程序优先级值将变小,即其优先级会变高,则其越快被执行
  • 调整进程优先级,在Linux下,就是调整进程的nice值
  • nice其取值范围是-20至19,一共有40个级别
  • 需要强调的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。nice值是进程优先级修正的修正数据

🕹️查看/修改进程优先级命令

        查看进程优先级的方式和查看进程信息的方式一样,可以使用ps命令或top命令来查看:

        使用ps命令查看进程PRI值和NI值:

        使用top命令查看已存在进程的nice值:

        修改进程优先级的方式是使用top命令:

  •         进入top后按“r”–>输入进程PID–>输入nice值
  •         需要注意的是普通用户不能修改nice值,只有root才可以修改进程的nice值

 进程的其他概念:

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰, 因此父子进程间PCB是独立的,代码可以共享, 但数据需要写时拷贝
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

结语

希望这篇关于 操作系统与进程 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【Linux】实现三个迷你小程序(倒计时,旋转指针,进度条)

【Linux】手把手教你从零上手gcc/g++编译器

【Linux】手把手教你从零上手Vim编辑器

【Linux】一文带你彻底搞懂权限

【Linux】基本指令(下)

【Linux】基本指令(中)

【Linux】基本指令(上)


相关文章:

【Linux】操作系统与进程

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) 目录 &#x1f4cc;操作系统 &#x1f38f;操作系统的概念 &#x1f38f;设计操作系统的目的 &#x1f38f;操作系统对进程的管理 &#x1f579;️操作系统为什么…...

【Linux】 LTG:移动硬盘部署Ubuntu24.04

Ubuntu To Go 是一种便携式的 Ubuntu 操作系统解决方案&#xff0c;允许用户将 Ubuntu 系统安装在 USB 驱动器或其他可移动存储设备上。这样&#xff0c;用户可以在任何支持 USB 启动的计算机上运行 Ubuntu&#xff0c;而无需在本地硬盘上进行安装。 准备工作 移动硬盘&#x…...

Android的logcat日志详解

Android log系统 logcat介绍 logcat是android中的一个命令行工具&#xff0c;可以用于得到程序的log信息。下面介绍 adb logcat中的详细参数命令以及如何才能高效的打印日志&#xff0c;或把日志保存到我们指定的位置。 可以输入 adb logcat --help&#xff0c;查看一下一些简…...

【Linux】:信号的保存和信号处理

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家带来信号的保存和信号处理相关代码和知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入…...

深入理解Java虚拟机:Jvm总结-Java内存区域与内存溢出异常

第二章 Java内存区域与内存溢出异常 2.1 意义 对于C、C程序开发来说&#xff0c;程序员需要维护每一个对象从开始到终结。Java的虚拟自动内存管理机制&#xff0c;让java程序员不需要手写delete或者free代码&#xff0c;不容易出现内存泄漏和内存溢出问题&#xff0c;但是如果…...

跨境电商必备保护账号的4个网络环境设置

在跨境电商的世界里&#xff0c;一个稳定可靠的网络环境就是你事业成功的关键&#xff01;但是&#xff0c;不稳定的IP很容易导致账号被封&#xff0c;让你的辛苦付之东流&#xff0c;相信许多小伙伴也经历过莫名其妙的账号封禁情况&#xff01; 为了让大家避免这种心痛的情况…...

Python+requests接口自动化测试框架实例教程

前段时间由于公司测试方向的转型&#xff0c;由原来的web页面功能测试转变成接口测试&#xff0c;之前大多都是手工进行&#xff0c;利用postman和jmeter进行的接口测试&#xff0c;后来&#xff0c;组内有人讲原先web自动化的测试框架移驾成接口的自动化框架&#xff0c;使用的…...

【网络安全】DNS重绑定原理详析

原创文章,不得转载。 文章目录 DNSDNS查询过程同源策略DNS重绑定攻击原理DNS重绑定攻击步骤DNS重绑定工具工具一工具二DNS 在网络中,访问网站实际上是通过其对应的 IP 地址实现的,然而,IP 地址往往难以记忆。因此,DNS(域名系统)应运而生。 DNS(Domain Name System)是…...

C语言初识编译和链接

目录 翻译环境和运行环境编译环境预编译编译词法分析语法分析语义分析 汇编 链接运行环境 翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指令&#xff08;⼆进制指令&…...

TrinityCore环境搭建

1)https://192.168.3.96:41797/soft/app root jianan2)mysql322bb8f85b0920d9 192.168.3.96 9f5c813fefbbc3aa3) su wow cd /home/wow/TrinityCore/TrinityCore-TDB335.22061/build cmake ../ -DCMAKE_INSTALL_PREFIX/home/wow/server3.5.5 #构建项目cmake ../ -DCMAKE_INSTALL…...

Proteus 仿真设计:开启电子工程创新之门

摘要&#xff1a; 本文详细介绍了 Proteus 仿真软件在电子工程领域的广泛应用。从 Proteus 的功能特点、安装与使用方法入手&#xff0c;深入探讨了其在电路设计、单片机系统仿真、PCB 设计等方面的强大优势。通过具体的案例分析&#xff0c;展示了如何利用 Proteus 进行高效的…...

microchip dspic3一些奇怪问题

UART初始化&#xff0c;导致一些MCU PIN输出低电平。 https://microchip.my.site.com/s/case/500V4000007jvz4IAA/detail 板子上电EEPROM读取不稳定&#xff0c;增加延时解决问题。 –If delay 1ms, will read EE Err –If delay 10ms, program and reset, will read EE err.…...

FinOps原则:云计算成本管理的关键

导语&#xff1a; FinOps 原则为我们提供了北极星&#xff08;North Star&#xff09;&#xff0c;在我们实践云财务管理时指导我们的活动。这些原则由 FinOps 基金会成员制定&#xff0c;并通过经验磨练出来。 北极星&#xff08;North Star&#xff09;的含义&#xff1a; …...

JavaScript之如何优化模板字符串的性能

在 JavaScript 中&#xff0c;优化模板字符串的性能可以从几个方面入手。模板字符串&#xff08;Template Literals&#xff09;是 ES6 引入的特性&#xff0c;它们使用反引号 () 包围&#xff0c;可以嵌入表达式并支持多行字符串。虽然模板字符串通常很方便&#xff0c;但在性…...

不能将类型“null”分配给类型“number | undefined”。ts(2322)

错误解释&#xff1a; 这个TypeScript错误表明你正在尝试将null赋值给一个预期为number类型或undefined类型的变量。在TypeScript中&#xff0c;null和undefined是有效的值&#xff0c;但通常我们希望它们与number类型不兼容。 解决方法&#xff1a; 检查导致错误的赋值语句&…...

Nginx部署前端Vue项目详细教程

文章目录 Nginx部署前端Vue项目详细教程准备工作打包Vue项目安装Nginx配置Nginx创建配置文件启用配置文件 部署Vue项目配置SSL&#xff08;可选&#xff09;测试和验证总结 Nginx部署前端Vue项目详细教程 本教程将详细介绍如何使用Nginx部署前端Vue项目&#xff0c;涵盖从项目…...

kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照以及工作常用总结

文章目录 kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照一、kvm 虚拟机命令行虚拟机操作(创建和删除)查看虚拟机virt-install创建一个虚拟机关闭虚拟机重启虚拟机销毁虚拟机 二、kvm 制作快照和恢复快照**创建快照**工作常见问题创建快照报错&#xff1a;&#xff1a;intern…...

内网安全-横向移动【3】

1.域横向移动-内网服务-Exchange探针 Exchange是一个电子右键服务组件&#xff0c;由微软公司开发。它不仅是一个邮件系统&#xff0c;还是一个消息与协作系统。Exchange可以用来构建企业、学校的邮件系统&#xff0c;同时也是一个协作平台&#xff0c;可以基于此开发工作流、…...

语言中的浮点数

浮点数相比定点数或者整数&#xff0c;为了处理小数点引入了指数&#xff0c;导致小数点的位置根据不同浮点数而不同&#xff0c;故名为Floating Point Number. 一般而言&#xff0c;IEEE754标准被大部分编程语言的浮点数使用&#xff0c;它节省了浮点数的保存空间。如不然&…...

Pyspark下操作dataframe方法(1)

文章目录 Pyspark dataframe创建DataFrame使用Row对象使用元组与scheam使用字典与scheam注意 agg 聚合操作alias 设置别名字段设置别名设置dataframe别名 cache 缓存checkpoint RDD持久化到外部存储coalesce 设置dataframe分区数量collect 拉取数据columns 获取dataframe列 Pys…...

注解实现json序列化的时候自动进行数据脱敏

最近在进行开发的时候遇到一个问题&#xff0c;需要对用户信息进行脱敏处理&#xff0c;原有的方式是写一个util类&#xff0c;在需要脱敏的字段查出数据后&#xff0c;显示掉用方法处理后再set回去&#xff0c;觉得这种方式能实现功能&#xff0c;但是不是特别优雅&#xff0c…...

使用Python下载文件的简易指南

在日常的数据处理、自动化任务或软件开发中&#xff0c;经常需要从网络上下载文件。Python作为一门功能强大的编程语言&#xff0c;提供了多种方法来实现文件的下载。本文将介绍几种常用的方法来使用Python下载文件&#xff0c;包括使用requests库和urllib库。 准备工作 在开…...

中秋国庆双节长假,景区迎来客流高峰,如何保障景区安全管理?

一、方案背景 近年来&#xff0c;国内旅游市场持续升温&#xff0c;节假日期间景区游客数量激增&#xff0c;给景区安全管理带来了巨大挑战。然而&#xff0c;景区安全风险意识不足、防护措施不完善、游客安全意识欠缺等问题依然存在&#xff0c;导致景区安全事故频发。随着中秋…...

多维数组转一维数组:探索 JavaScript 中的数组扁平化

在 JavaScript 编程中&#xff0c;我们经常会遇到需要将多维数组转换为一维数组的情况。无论是处理复杂的数据结构还是进行数据的进一步操作&#xff0c;数组扁平化都是一个常见且有用的技术。本文将介绍几种在 JavaScript 中将多维数组转换为一维数组的方法。 什么是数组扁平…...

配环境时的一些记录

连centos&#xff1a;正常连就好&#xff08;密码验证码&#xff09;连rocky&#xff1a;需要在centos上连&#xff0c;终端里直接ssh [rocky_ip]&#xff1b;在vscode中需要&#xff1a; 修改配置文件&#xff1a;打开命令面板&#xff08;ctrlshiftp&#xff09; -> 输入并…...

如何解析域名到网站?

在现代互联网中&#xff0c;域名解析是用户访问网站的关键过程。用户通过输入易于记忆的域名来访问网站&#xff0c;而背后则是复杂的域名解析机制将域名转换为服务器的IP地址&#xff0c;使得浏览器能够找到并加载目标网站。聚名网详细介绍域名解析的过程及其相关技术。 一、…...

【F172】基于Springboot+vue实现的智能菜谱系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 项目描述 近些年&#xff0c;随着中国经济发展&#xff0c;人民的…...

Spring-AOP核心源码、原理详解前篇

本文主要分4部分 Aop原理介绍介绍aop相关的一些类通过源码详解aop代理的创建过程通过源码详解aop代理的调用过程Aop代理一些特性的使用案例 Spring AOP原理 原理比较简单&#xff0c;主要就是使用jdk动态代理和cglib代理来创建代理对象&#xff0c;通过代理对象来访问目标对象…...

Reflection反射——Class类

概述 在Java中&#xff0c;除了int等基本类型外&#xff0c;Java的其他类型全部都是class&#xff08;包括interface&#xff09;。例如&#xff1a; String、Object、Runnable、Exception…… Java反射机制是Java语言的一个重要特性。在学习Java反射机制前&#xff0c;需要了…...

王朝兴替的因果

天道好轮 回&#xff0c;苍天饶过谁。王朝兴亡&#xff0c;天道无情。 而其因果循环&#xff0c;天道之森严&#xff0c;让人敬畏。 王朝创业帝王造下什么业&#xff0c;后世子孙在兴替之时&#xff0c;往往要承担何种果 报。 中国几千年的王朝史&#xff0c;因 果循环&…...