Linux | Linux进程万字全解:内核原理、进程状态转换、优先级调度策略与环境变量
目录
1、从计算机组成原理到冯诺依曼架构
计算机系统的组成
冯诺依曼体系
思考:为什么计算机不能直接设计为 输入设备-CPU运算-输出设备 的结构?
2、操作系统(Operator System)
概念
设计OS的目的
描述和组织被管理对象
3、进程
基本概念
进程id和父进程id
进程 ID (PID):
父进程 ID (PPID):
C语言利用系统调用接口获取PID、PPID:
进程描述-PCB进程控制块
task_struct内容分类
查看进程
简单的进程监控脚本
在C语言中通过系统调用fork函数创建进程
fork() 系统调用:
示例1:使用 fork() 创建新进程,并通过返回值区分父子进程
示例2:使用 fork() 创建新进程,并打印相关信息
4、进程状态
进程状态概览
僵尸状态(子进程结束却没被父进程回收)
形成僵尸进程的条件
僵尸进程的危害
示例代码:创建并观察僵尸进程
孤儿状态(父进程结束子进程还在)
孤儿进程的形成:
孤儿进程的处理:
示例:孤儿进程的形成和处理:
5、进程调度与优先级
基本概念
查看系统进程
PRI 和 NI
操作:在bash中通过pid调整特定进程优先级
6、环境变量:操作系统的隐秘力量
基本概念
常见环境变量
查看和设置环境变量
环境变量的组织方式
示例1:通过main函数参数获取
示例2:通过extern变量获取
示例3:通过getenv()和putenv()接口操作单个环境变量
环境变量和普通变量的区别:环境变量具有全局属性
Linux进程
在现代计算机系统中,Linux操作系统以其开源、灵活和强大的特性,成为服务器和嵌入式系统的首选。了解Linux的进程管理机制对于系统管理员和开发者来说至关重要。
1、从计算机组成原理到冯诺依曼架构
计算机系统的组成
计算机组成原理告诉我们,所有的计算机系统都由一下结构组成:
- 输入设备:如键盘和鼠标,用于向计算机输入信息。
- 中央处理器(CPU):计算机的大脑,负责处理数据和执行命令。
CPU分为:运算器和控制器
运算器——算数运算、逻辑运算
控制器——响应外部事件、如拷贝磁盘数据到内存当中
- 存储器:内存(RAM)用于临时存储程序和数据。
- 输出设备:如显示器和打印机,用于展示信息和打印文档。

冯诺依曼体系
冯·诺依曼架构的最关键特点是程序指令和数据都存储在内存中,并且CPU可以直接访问内存来读取指令和数据。所有的输入和输出操作都是通过内存来进行的,即数据首先被写入内存,然后CPU从内存中读取数据进行处理,处理结果再写回内存,最后通过输出设备显示或打印出来。通俗的说,CPU大脑只和内存打交道,不和其它设备直接沟通。内存在冯诺依曼架构中充当中间件的作用。

笔记:我们常说的IO流是指内存和外设之间的通信!
思考:为什么计算机不能直接设计为 输入设备-CPU运算-输出设备 的结构?
其中一个原因是,计算机需要存储程序和数据。如果没有存储器,CPU将无法记住程序指令和处理的数据。但更本质的原因是CPU的运算速度远远超过大多数输入和输出设备,如果没有内存作为数据缓冲区,CPU在等待慢速的输入设备(如键盘或鼠标)提供数据或等待输出设备(如打印机或显示器)处理数据时,将会浪费大量计算资源。(CPU的执行过程也是流水线 木桶原理告诉我们 计算总时间取决于木桶的短板~)
2、操作系统(Operator System)
操作系统(Operating System,简称OS)是计算机系统中最基本的系统软件,它负责管理和控制计算机硬件和软件资源。操作系统在整个计算机软硬件架构中,定位为“管理”的软件,它处于应用软件和硬件之间的中间层,使用面向对象的思想,先描述资源,再管理资源,使得用户能够方便地使用计算机。
概念
操作系统是一组程序,它提供了计算机硬件和用户应用程序之间的接口。操作系统的主要功能包括:
- 内核:操作系统的核心部分,负责进程管理、内存管理、文件系统管理和设备驱动程序管理等。
- 其他程序:如函数库、Shell(命令行界面)、图形用户界面(GUI)等,这些程序为用户提供了与操作系统交互的接口。
设计OS的目的
- 与硬件交互:操作系统是计算机硬件的直接管理者,它通过内核与硬件进行交互,实现对硬件资源的控制。
- 管理软硬件资源:操作系统负责分配和管理CPU时间、内存、存储设备和输入输出设备等资源。
- 提供执行环境:为用户程序(应用程序)提供执行所需的环境,包括文件系统、网络通信、安全机制等。
描述和组织被管理对象
- 硬件资源:CPU、内存、存储设备、输入输出设备等。
- 软件资源:用户程序、系统程序、库文件等。
3、进程
基本概念
- 课本概念:进程是程序的一个执行实例,是正在执行的程序。
- 内核观点:进程是分配系统资源(如CPU时间和内存)的实体。
进程id和父进程id
进程 ID(Process ID,PID)和父进程 ID(Parent Process ID,PPID)是操作系统中用于标识和管理进程的关键属性
进程 ID (PID):
- 每个运行中的进程都有一个唯一的数字标识符,称为 PID。
- PID 是由操作系统分配的,用于区分系统中的每个进程。
- 它通常从1开始递增,但操作系统重启后会重置。
- 可以通过命令如
ps来查看系统中所有进程的 PID。
父进程 ID (PPID):
- 每个进程都有一个父进程,除了初始进程(通常 PID 为1 的进程,如 init 进程)。
- PPID 是指启动当前进程的父进程的 PID。
- 父进程可以控制子进程的执行,例如发送信号、终止子进程等。
- 当父进程终止时,子进程通常会被 init 进程接管,init 进程的 PID 通常为 1.
C语言利用系统调用接口获取PID、PPID:
getpid():这是一个系统调用,用于获取调用进程的 PID。getppid():这也是一个系统调用,用于获取调用进程的父进程的 PID。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {printf("pid: %d\n", getpid());printf("ppid: %d\n", getppid());return 0;
} 进程描述-PCB进程控制块
- PCB是存储进程信息的数据,结构进程的属性集合被存储在PCB中。
- 在Linux操作系统中,描述进程的结构体是
task_struct。 - 在Linux内核源代码中,所有进程以
task_struct双向链表的形式被组织起来
task_struct内容分类
- 标示符:进程的唯一标识符。
- 状态:包括任务状态、退出代码、退出信号等。
- 优先级:进程相对于其他进程的优先级。
- 程序计数器:指向程序中即将执行的下一条指令的地址。
- 内存指针:指向程序代码、进程数据以及共享内存的指针。
- 上下文数据:处理器寄存器中的数据,用于进程切换时保存和恢复状态。
- I/O状态信息:包括I/O请求、分配的I/O设备和使用的文件列表。
- 记账信息:可能包括处理器时间、使用的时钟数、时间限制和账号信息。
- other...
查看进程
- 目录
/proc下存在进程的相关信息(进程产生时创建、销毁时删除,目录名为进程PID),进程信息可以通过/proc系统文件夹查看,例如/proc/1包含PID为1的进程信息。 - 用户级工具如
top和ps也可以用来获取进程信息。
🔔常用命令解释:
ps axj | head -1 && ps axj | grep ...
ps axj:
ps:进程状态命令。
ax:显示所有进程,包括其他用户的进程。a表示显示其他用户的进程,x表示显示没有控制终端的进程。
j:使用 jobs 格式来显示进程信息,这种格式将进程的相关信息以易于阅读的方式展示,包括进程的父子关系。
head -1:
head:一个命令,用于显示文件的开始部分,默认情况下显示前10行。
-1:选项,表示只显示一行。在这个上下文中,它与ps axj结合使用,只显示进程列表的第一行,这通常是列标题。
ps axj | head -1用于打印ps命令字段含义。
&&:
- 逻辑与操作符。用来执行
&&前后两条命令则执行后面的命令。
grep ...:
grep:一个文本搜索工具,用于搜索包含指定模式的行。
...:需要搜索的进程名称。
ps axj | grep ...用于打印ps命令经过grep命令筛选后特定的字段内容。首先显示所有进程的标题行,如果成功显示,则继续执行第二个命令,即显示所有进程的列表,并过滤出包含特定模式的进程。
简单的进程监控脚本
在ps axj | head -1 && ps axj | grep ...的基础上可以设计一个循环shell脚本,一秒钟查询一次进程状态。
while :; do ps axj | head -1 && ps axj | grep ...; echo ""; sleep 1; done 
在C语言中通过系统调用fork函数创建进程
fork() 是一个在 Unix 和类 Unix 操作系统中创建新进程的系统调用。它是进程创建的基础,并且是多任务和多线程编程中非常重要的一部分。
fork() 系统调用:
fork()创建一个新的进程,这个新进程是调用进程的一个副本。fork()返回两次:一次在父进程中(返回子进程的 PID),一次在子进程中(返回 0)。- 如果
fork()调用失败,它会在父进程中返回-1,并且设置全局变量errno以指示错误。 fork()之后,父进程和子进程将从fork()调用之后的代码点继续执行,这可能导致代码的重复执行。通常使用if语句来区分父进程和子进程的行为。- 子进程继承了父进程的所有资源,但是它们拥有不同的 PID 和 PPID。
- 在使用
fork()创建大量子进程时,需要考虑资源限制和僵尸进程问题(后续进程状态介绍)。
示例1:使用 fork() 创建新进程,并通过返回值区分父子进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {int ret = fork();if (ret < 0) {perror("fork");return 1;} else if (ret == 0) { // 子进程printf("I am child : %d!, ret: %d\n", getpid(), ret);} else { // 父进程printf("I am father : %d!, ret: %d\n", getpid(), ret);}sleep(1);return 0;
} 示例2:使用 fork() 创建新进程,并打印相关信息
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {int ret = fork();printf("hello proc : %d!, ret: %d\n", getpid(), ret);sleep(1);return 0;
} 4、进程状态
Linux 系统中的进程管理是操作系统的核心功能之一。Linux内核定义了多种进程状态,包括运行(R)、睡眠(S)、不可中断睡眠(D)、停止(T)、追踪停止(t)、死亡(X)和僵尸(Z)。
进程状态概览
在 Linux 内核中,进程(或称为任务)可以处于以下状态:
- 运行状态 (R - Running):
- 进程正在使用 CPU,或者在 CPU 运行队列中等待被调度。
- 睡眠状态 (S - Sleeping):
- 进程正在等待某个事件发生,如网络响应或文件 I/O 完成。这种睡眠是可中断的,进程可以被唤醒。
- 磁盘休眠状态 (D - Disk Sleep):
- 进程正在进行 I/O 操作,如磁盘读写,但无法被中断。这种状态也称为不可中断睡眠状态。
- 停止状态 (T - Stopped):
- 进程被
SIGSTOP信号停止,通常用于调试或系统管理。进程可以通过SIGCONT信号恢复运行。- 追踪停止状态 (t - Tracing Stop):
- 进程因为某些原因被系统调用或工具追踪并停止,通常用于系统分析和监控。
- 死亡状态 (X - Dead):
- 进程已经结束其执行,但尚未从进程表中完全移除。这是一个过渡状态,系统将很快回收其资源。
- 僵尸状态 (Z - Zombie):
- 进程已经结束,但父进程尚未读取其退出状态。僵尸进程占用系统资源,尤其是进程 ID,直到父进程调用
wait()或waitpid()函数。
/*
* 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 */
}; 僵尸状态(子进程结束却没被父进程回收)
僵尸进程(Zombie Process)是 Linux 和类 Unix 系统中一种特殊的进程状态。在这种状态下,进程已经完成其执行,但它的进程描述符(PCB)仍然保留在系统中。这种状态的进程不占用 CPU 资源,但它们仍然占用一个进程 ID(PID)和其他一些资源。
形成僵尸进程的条件
- 子进程退出:子进程完成其任务后调用
exit()或者返回从main()函数,这会导致子进程退出。 - 父进程未读取状态:如果父进程没有调用
wait()或waitpid()来读取子进程的退出状态,子进程就会变成僵尸状态。
僵尸进程的危害
- 占用进程 ID:僵尸进程继续占用一个进程 ID,这在系统资源有限的情况下可能是个问题。
- 内存泄漏:虽然僵尸进程不占用 CPU 资源,但它们仍然保留在进程表中,进程表本质是一个结构体,也需要占用系统内存资源,造成了内存泄露
示例代码:创建并观察僵尸进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t id = fork();if (id < 0) {perror("fork");return 1;} else if (id > 0) { // 父进程printf("Parent[%d] is sleeping...\n", getpid());sleep(30); // 父进程睡眠,不读取子进程状态,形成僵尸进程} else if(id == 0){ // 子进程printf("Child[%d] is beginning...\n", getpid());sleep(5);exit(0);}return 0;
} - 程序开始时,父进程被创建。
- 父进程通过
fork()创建子进程。 - 子进程打印开始消息,休眠5秒,然后退出。
- 父进程打印正在睡眠的消息,然后休眠30秒。由于父进程在sleep时间内不检查子进程的状态,子进程在退出后会变成僵尸进程。

孤儿状态(父进程结束子进程还在)
孤儿进程(Orphan Process)是其父进程已终止,但子进程仍在运行的进程。在类 Unix 系统中,孤儿进程会被 init 进程(通常是 PID 为 1 的进程)领养,并最终由 init 进程回收。
孤儿进程的形成:
- 父进程退出:父进程由于某种原因(如正常退出、被终止等)而结束运行。
- 子进程仍在运行:在父进程退出时,如果有任何子进程仍在运行,这些子进程就会变成孤儿进程。
孤儿进程的处理:
init进程领养:系统会自动将孤儿进程的父进程设置为init进程(PID 为 1)。- 状态变更:孤儿进程在结束运行后,会进入僵尸状态(Zombie State),等待
init进程读取其退出状态。 - 资源回收:
init进程会周期性地检查并回收孤儿进程的资源,包括其进程描述符等。
示例:孤儿进程的形成和处理:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid = fork(); // 创建子进程if (pid < 0) {perror("fork failed");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程printf("Child process, PID: %d, PPID: %d\n", getpid(), getppid());// 子进程继续运行,模拟父进程退出后的场景sleep(10);} else {// 父进程退出,子进程成为孤儿进程printf("Parent process, PID: %d, exiting and leaving child orphaned.\n", getpid());sleep(3);_exit(0);}// 子进程代码不会被执行,因为父进程已经退出return 0;
} 在这个示例中,父进程创建了一个子进程,然后立即退出。这导致子进程成为孤儿进程。在实际系统中,init 进程会接管这个孤儿进程,并在其退出后回收资源。

5、进程调度与优先级
在 Linux 系统中,进程优先级决定了 CPU 资源的分配顺序。进程优先级可以通过nice值调整,nice值的范围是-20至19,nice值越小进程优先级越高。进程调度是操作系统的核心功能之一,它决定了进程执行的顺序。
基本概念
- 进程优先权(Priority):决定了进程被 CPU 执行的先后顺序。优先权高的进程会优先获得 CPU 时间。
- 多任务环境:在多任务环境中,合理配置进程优先级可以显著改善系统性能。
查看系统进程
在 Linux 或 Unix 系统中,可以使用 ps -l 命令来查看系统进程列表。

输出将包括以下重要信息:
- UID:用户 ID,表示执行进程的用户身份。
- PID:进程 ID,是进程的唯一标识。
- PPID:父进程 ID,表示该进程是由哪个父进程创建的。
- PRI:进程的优先级。
- NI:nice 值,表示进程优先级的修正数值。
PRI 和 NI
- PRI:进程的原始优先级,数值越小表示优先级越高。
- NI:nice 值,用于调整进程的优先级。计算新的优先级公式为
PRI(new) = PRI(old) + NI。 - nice 值的范围:从 -20 到 19,共 40 个级别。正值表示降低进程优先级,负值表示提高进程优先级。
注意:nice 值不是进程的优先级,而是进程优先级允许调整的范围。可以将其视为对原始优先级的一个修正。通过调整 nice 值,可以控制进程的相对优先级,从而影响 CPU 资源的分配。
最终,操作系统更具PRI(new)的值,按从小到大的优先级执行。
操作:在bash中通过pid调整特定进程优先级
- 使用
top命令可以动态查看进程优先级。 - 按
r键来调整指定pid进程的 nice 值。

6、环境变量:操作系统的隐秘力量
引入:我们知道,在 Linux 系统中,确实“一切皆文件”,命令的本质是一个可执行程序(大部分是c语言编译而来的可执行程序),命令名其实就是文件名,命令可以不需要完整路径就能执行。例如:只需要输入ls命令就可以执行对应的程序,获取目录内的文件。但是,为什么我们自己写的程序必须要带完整的文件路径才可以执行(./main),而命令程序只需要文件名即可?这背后的原理涉及到 Linux 的文件系统和环境变量,尤其是 PATH 环境变量。
基本概念
环境变量为操作系统、系统上的应用程序和用户shell提供了一个传递配置信息的方法。它们可以告诉系统在哪里找到所需的文件,如何配置特定的程序,或者在shell中定义别名等。
常见环境变量
- PATH:定义了操作系统搜索可执行文件的目录顺序。例如,当你在终端输入一个命令时,系统会在PATH变量指定的目录中查找这个命令,发现相应文件就可以直接执行(相当于自动补全文件路径)。当我们把我们自己写的代码目录放入PATH环境变量之后,也能向命令一样只需要输入文件名即可执行。(相关的修改操作后半部分介绍~)

- HOME:指向用户的主目录。当你登录系统时,这是你的默认工作目录。
- SHELL:表示当前用户使用的shell类型,通常的值是
/bin/bash。
查看和设置环境变量
- 查看环境变量:可以使用
echo $NAME命令来打印特定的环境变量值,其中NAME是环境变量的名称。 - 设置环境变量:
- 使用
export命令创建或修改环境变量,如export PATH=$PATH:/new/directory/path。 - 使用
env命令可以查看所有当前的环境变量。
- 使用
- 清除环境变量:使用
unset命令可以删除一个环境变量。 - 显示所有本地变量:使用
set命令可以显示当前shell会话中定义的所有本地变量和环境变量。
📌1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量
环境变量的组织方式
程序在运行时,main函数第三个参数(也是最后一个参数)会被转入一张环境变量表

示例1:通过main函数参数获取
#include<stdio.h>
int main(int argc, char* argv, char** env)
{int i = 0;while(env[i]){printf("env[%d]->%s\n",i,env[i]);i++;}return 0;
} 
示例2:通过extern变量获取
#include <stdio.h>
int main()
{extern char **environ;int i = 0;for(; environ[i]; i++){printf("env[%d]->%s\n", i, environ[i]);}return 0;
} 
示例3:通过getenv()和putenv()接口操作单个环境变量
getenv 和 putenv 是两种用于处理环境变量的函数,它们分别用于获取和设置环境变量的值。下面是对这两个函数的介绍,包括它们所属的头文件、函数原型、参数、返回值以及一些使用示例。
getenv
- 头文件:
#include <stdlib.h> - 函数原型:
char *getenv(const char *name); - 参数:
name:一个指向以 null 结尾的字符串的指针,指定要查询的环境变量名称。
- 返回值:
- 如果环境变量存在,返回指向该环境变量值的指针。
- 如果环境变量不存在,返回
NULL。
#include <stdio.h>
#include <stdlib.h>int main() {const char *homeDir = getenv("HOME");if (homeDir != NULL) {printf("The HOME environment variable is set to: %s\n", homeDir);} else {printf("The HOME environment variable is not set.\n");}return 0;
} putenv
- 头文件:
#include <stdlib.h>(在某些系统上可能需要#include <unistd.h>) - 函数原型:
int putenv(char *string); - 参数:
string:一个指向以 null 结尾的字符串的指针,该字符串应该包含环境变量的名称和值,格式为name=value。
- 返回值:
- 成功时返回 0。
- 失败时返回非零值。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {// 设置环境变量const char *envVar = "MY_VAR=value";if (putenv((char *)envVar) == 0) {printf("Environment variable set successfully.\n");} else {perror("Failed to set environment variable");}// 验证设置是否成功const char *value = getenv("MY_VAR");if (value != NULL) {printf("MY_VAR is now set to: %s\n", value);} else {printf("MY_VAR is not set.\n");}return 0;
} - 使用
putenv时,传入的字符串string必须以name=value的格式存在,并且string指向的内存在函数调用后不应被释放或修改,因为putenv可能会修改这个字符串。 - 在多线程环境中,使用
putenv可能不是线程安全的。在这种情况下,可以考虑使用setenv和unsetenv(如果可用),这些函数提供了线程安全的替代。 - 环境变量的更改通常只影响当前进程及其子进程,不会影响其他进程或父进程的环境变量。
环境变量和普通变量的区别:环境变量具有全局属性
环境变量具有全局属性,意味着它们可以在操作系统的不同进程之间共享。当一个程序运行时,它通常会从其父进程那里继承环境变量。这种继承机制允许程序访问由操作系统或其它程序设置的配置信息。
当你在命令行中设置一个环境变量,比如使用 export my_env ="lihongyu" 命令,实际上是在当前的shell会话中设置了这个变量。这个变量会立即在当前shell会话中可用,并且所有从这个shell启动的子进程也会继承这个变量。
如果你只设置环境变量而不使用 export 命令,比如 my_env="lihongyu",那么这个变量只会在当前的shell会话中存在,而不会被子进程继承。这是因为只有通过 export 命令,变量才会被标记为可导出,从而被子进程继承。
#include<stdio.h>
#include<stdlib.h>
int main()
{const char* env = getenv("my_env");if(env){printf("%s\n", env);}return 0;
} 
一个简单的实验,发现环境变量的继承和普通变量的区别在于:
- 作用域:普通变量只在当前shell会话中有效,而环境变量可以跨会话和进程边界。
- 继承:环境变量可以被子进程继承,而普通变量则不能。
- 生命周期:普通变量的生命周期仅限于当前shell会话,环境变量则可以持续存在于操作系统中,直到被显式地修改或删除。
相关文章:
Linux | Linux进程万字全解:内核原理、进程状态转换、优先级调度策略与环境变量
目录 1、从计算机组成原理到冯诺依曼架构 计算机系统的组成 冯诺依曼体系 思考:为什么计算机不能直接设计为 输入设备-CPU运算-输出设备 的结构? 2、操作系统(Operator System) 概念 设计OS的目的 描述和组织被管理对象 3、进程 基本概念 进程id和父进程…...
VBA技术资料MF184:图片导入Word添加说明文字设置格式
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...
在函数设计中应用单一职责原则:函数分解与职责分离
在函数设计中应用单一职责原则:函数分解与职责分离 引言 单一职责原则(Single Responsibility Principle, SRP)是面向对象设计原则中的核心原则之一,强调一个类或函数应该只有一个责任或理由去改变。在函数设计中,应…...
多线程锁机制面试
目录 乐观锁的底层原理 ReentrantLock的实现原理 读写锁 ReentrantReadWriteLock synchronized 底层原理 Lock和synchronized的区别 乐观锁的底层原理 版本号机制 在数据库表中添加一个版本号字段(如 version),每次更新数据时都会将版本号…...
《SQL 中计算地理坐标两点间距离的魔法》
在当今数字化的世界中,地理数据的处理和分析变得越来越重要。当我们面对一个包含地理坐标数据的表时,经常会遇到需要计算两点之间距离的需求。无论是在物流配送路线规划、地理信息系统应用,还是在基于位置的服务开发中,准确计算两…...
微服务可用性设计
一、隔离 对系统或资源进行分割,实现当系统发生故障时能限定传播范围和影响范围。进一步的,通过隔离能够降低系统之间得耦合度,使得系统更容易维护和扩展。某些业务场景下合理使用隔离技巧也能提高整个业务的性能。我理解隔离本质就是一种解…...
【扒代码】dave readme文档翻译
jerpelhan/DAVE (github.com) 摘要 低样本计数器估算选定类别对象的数量,即使在图像中只有少量或没有标注样本的情况下。目前最先进的技术通过对象位置密度图的总和来估算总数量,但这种方法无法提供单个对象的位置和大小,这对于许多应用来说…...
c语言---文件
这一节我准备分三个部分来带领大家了解文件 ——一、有关文件的基础知识 ————二、文件的简单操作 ————————三、文件结束的判定 ————————————四、文件缓冲区 一、文件的基础知识: 首先在了解文件之前,我们需要了解C/C程序内存…...
Windows系统下Go安装与使用
step1: 下载go语言SDK 下载地址:https://go.dev/dl/ 下载后选择合适位置安装即可,我选择D盘 在安装完成后,可以通过go env 命令检测是否安装成功。在“命令提示符”界面输入“go env”命令,如果显示如下类似结果则说明…...
day24-测试之接口测试基础
目录 一、接口的定义 二、接口的优点 三、API接口 四、接口测试流程 五、网络基础概念 六、HTTP和RURL 七、get和post请求 八、数据格式 九、状态码 十、restful风格 十一、接口工具 一、接口的定义 程序之间协作所要遵循的一套规范、标准 二、接口的优点 2.1.责任…...
TSN 交换机
TSN(Time-Sensitive Networking)交换机是一种支持时间敏感网络协议的网络交换设备,用于在以太网网络中实现低延迟、高确定性的数据传输。TSN 是一组 IEEE 802 标准的集合,旨在通过标准化的方式,将传统的以太网扩展到需…...
针对thinkphp站点的漏洞挖掘和经验分享
0x1 前言 浅谈 目前在学习和研究thinkphp相关漏洞的打法,然后最近对于thinkphp资产的收集方面有了一个简单的认识,然后写一篇新手看的thinkphp相关的漏洞收集和挖掘的文章来分享下。然后后面是给师傅们分享下后台文件上传,然后直接打一个ge…...
MySQL数据库入门,pycharm连接数据库—详细讲解
一.安装MySQL 1.常用MySQL5.7,首先安装MySQL, (一) (二) (三) (四) (五) 2.配置环境变量 打开MySQL安装路径,在其中找到…...
.bat文件快速运行vue项目
如何使用bat文件快速运行vue项目? 新建个文件,改名为serve.bat。 在文件中写入以下内容: # cd 项目路径 cd D:\projects\xxx npm run serve pausecd 项目所在的路径 npm run dev/serve ,取决于项目的启动方法,打…...
数据结构(邓俊辉)学习笔记】优先级队列 07——堆排序
1.算法 作为完全二叉堆的一个应用,这节来介绍堆排序算法。 是的,谈到优先级队列,我们很自然地就会联想到排序。因为就其功能而言,包括完全二叉堆在内的任何一种优先级队列都天生地具有选取功能,也就是选取其中的最大…...
npm install pnpm -g 报错的解决方法
npm install pnpm -g 报错的解决方法 npm error code ETIMEDOUT npm error errno ETIMEDOUT npm error network request to https://registry.npmjs.org/pnpm failed, reason: npm error network This is a problem related to network connectivity. npm error network In mo…...
集师知识付费小程序开发
智慧生活,从选择一款优质知识付费小程序起航 在这个信息爆炸的时代,知识成为了最宝贵的财富。我们渴望不断学习,提升自我,追求更高品质的生活。而一款优质的知识付费小程序,就如同照亮前行道路的明灯。 它是知识的宝库…...
前端开发提效工具——用户自定义代码片段
做开发总是会有大量的代码要写,但是有时候某些代码是非常基础但是很多,我们就可以把这一部分整合起来,使用一个很简短的关键字来快速唤出。 如何新建这样的代码段? 1.在VSCode当中找到Snippets,然后点击 2.之后会弹出…...
docker容器安全加固参考建议——筑梦之路
这里主要是rootless的方案。 在以 root 用户身份运行 Docker 会带来一些潜在的危害和安全风险,这些风险包括: 容器逃逸:如果一个容器以 root 权限运行,并且它包含了漏洞或者被攻击者滥用,那么攻击者可能会成功逃出容器…...
基于 Appium 的 App 爬取实战
除了运行 Appium 的基本条件外,还要一个日志输出库 安装: pip install loguru 思路分析 首先我们观察一下整个 app5 的交互流程,其首页分条显示了电影数据, 每个电影条目都包括封面,标题, 类别和评分 4…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
