Linux多进程和多线程(一)-进程的概念和创建
- 进程
- 进程的概念
- 进程的特点如下
- 进程和程序的区别
- LINUX进程管理
- getpid()
- getppid()
- 进程的地址空间
- 虚拟地址和物理地址
- 进程状态管理
- 进程相关命令
- ps
- top
- pstree
- kill
- 进程的创建
- 并发和并行
- fork()
- 父子进程执行不同的任务
- 创建多个进程
- 进程的退出
- exit()和_exit()
- exit()函数让当前进程退出,并且刷新缓冲区
- _exit()
- exit()和_exit()
- 进程的等待
- wait()函数 和 waitpid()函数
- wait()函数
- 创建⼀个⼦进程, 延时 3s 后退出, ⽗进程等待⼦进程退出
- waitpid()函数
- 函数原型
- 函数参数
- wait()函数
- wait()函数 和 waitpid()函数
- 进程的替换
- 在 Linux 系统中提供了⼀组⽤于进程替换的替换,共有 6 个函数
- 示例:通过 execl 函数族执⾏ ls -l 命令
进程
进程的概念
进程(Process)是操作系统对一个正在运行的程序的一种抽象。它是系统运行程序的最小单位,是资源分配和调度的基本单位。
进程的特点如下
-
进程是⼀个独⽴的可调度的活动, 由操作系统进⾏统⼀调度, 相应的任务会被调度到cpu 中进⾏执⾏
-
进程⼀旦产⽣,则需要分配相关资源,同时进程是资源分配的最⼩单位
进程和程序的区别
- 程序是静态的,它是⼀些保存在磁盘上的指令的有序集合,没有任何执⾏的概念
- 进程是⼀个动态的概念,它是程序执⾏的过程,包括了动态创建、调度和消亡的整个过程
- 并⾏执⾏ : 表示多个任务能够同时执⾏,依赖于物理的⽀持,⽐如 cpu是4核⼼,则可以同时执⾏4个任务
- 并发执⾏ : 在同⼀时间段有多个任务在同时执⾏,由操作系统调度算法来实现,⽐较典型的就是时间⽚轮转
LINUX进程管理
在 Linux 系统中管理进程使⽤树型管理⽅式
- 每个进程都需要与其他某⼀个进程建⽴ ⽗⼦关系, 对应的进程则叫做 ⽗进程
- Linux 系统会为每个进程分配 id , 这个 id 作为当前进程的唯⼀标识, 当进程结束, 则会回收
进程的 id 与 ⽗进程的 id 分别可以通过 getpid() 与 getppid() 来获取
getpid()
#include <unistd.h>pid_t getpid(void);
该函数用来获取当前进程的 id
getppid()
#include <unistd.h>pid_t getppid(void);
该函数用来获取当前进程的⽗进程的 id
进程的地址空间
-
⼀旦进程建⽴之后, 系统则要为这个进程分配相应的资源, ⼀般系统会为每个进程分配 4G 的地址空间
-
-
4G 的进程地址空间主要分为两部分:
0 - 3G : ⽤户空间
3G - 4G : 内核空间 -
⽤户空间⼜具体分为如下区间
stack : 存放⾮静态的局部变量
heap : 动态申请的内存
.bss : 未初始化过的全局变量(包括初始化为 0 的, 未初始化过的静态变量 (包括初始化为 0)
.data : 初始化过并且值不为 0 的全局变量, 初始化过的不为 0 静态变量
.rodata : 只读变量(字符串之类)
.text : 程序⽂本段(包括函数,符号常量)
- 当⽤户进程需要通过内核获取资源时, 会切换到内核态运⾏, 这时当前进程会使⽤内核空间的资源⽤户需要切换到内核态运⾏时, 主要是通过 系统调⽤
虚拟地址和物理地址
- 虚拟地址 : 程序运行时使用的地址, 由操作系统管理, 程序只能通过虚拟地址访问内存
- 物理地址 : 实际物理内存中存储数据的地址, 由硬件管理, 程序只能通过物理地址访问内存
- 虚拟地址和物理地址的转换关系由操作系统完成, 程序只能通过虚拟地址访问内存
- 虚拟地址空间和物理地址空间的映射关系由操作系统完成, 程序只能通过虚拟地址访问内存
在 cpu 中有⼀个硬件 MMU(内存管理单元) , 负责虚拟地址与物理地址的映射管理以
及虚拟地址访问
操作系统可以设置 MMU 中的映射内存段
在操作系统中使⽤虚拟地址空间主要是基于以下原因:
直接访问物理地址, 会导致地址空间没有隔离, 很容易导致数据被修改
通过虚拟地址空间可以实现每个进程地址空间都是独⽴的,操作系统会映射到不⽤的
物理地址区间,在访问时互不⼲扰.
进程状态管理
进程是动态过程,操作系统内核在管理整个动态过程时会使⽤了
状态机,
- 给不同时间节点设计⼀个状态,通过状态来确定当前的过程进度
- 在管理动态过程时,使⽤状态机是⼀种⾮常好的⽅式
进程的状态⼀般分为如下
- 运⾏态 (TASK_RUNNING) : 此时进程或者正在运⾏,或者准备运⾏, 就绪或者正在进⾏都属于运⾏态
- 睡眠态 () : 此时进程在等待⼀个事件的发⽣或某种系统资源
- 可中断的睡眠 (TASK_INTERRUPT) : 可以被信号唤醒或者等待事件或者资源就绪
- 不可中断的睡眠 (TASK_UNTERRUPT) : 只能等待特定的事件或者资源就绪
- 停⽌态 (TASK_STOPPED) : 进程暂停接受某种处理。例如:gdb 调试断点信息处理。
- 僵死态(TASK_ZOMBIE):进程已经结束但是还没有释放进程资源
进程相关命令
ps
参数:
- -e 显示所有进程
- -f 显示进程详细信息
- -l 显示进程详细信息,包括线程信息
- -u 显示指定用户的进程
- -aux 显示所有进程,包括其他用户的进程
ps -aux
ps -ef | grep " 进程名 " # 查找进程
top
实时显示系统中进程的运行状态
top [-] [d delay] [q] [c] [S] [s] [i] [n] [b]
选项:
- d : 改变显示的更新速度,或是在交谈式指令列 (interactive command) 按 s
- q : 没有任何延迟的显示速度,如果使⽤者是有 superuser 的权限,则 top 将会以最⾼的优先序执⾏
- c : 切换显示模式,共有两种模式,⼀是只显示执⾏档的名称,另⼀种是显示完整的路径与名称
- S : 累积模式,会将⼰完成或消失的⼦进程 (dead child process) 的 CPU time 累积起来
- s : 安全模式,将交谈式指令取消, 避免潜在的危机
- i : 不显示任何闲置 (idle) 或⽆⽤ (zombie) 的进程
- n : 更新的次数,完成后将会退出 top
- b : 批次档模式,搭配 “n” 参数⼀起使⽤,可以⽤来将 top 的结果输出到档案内
top - 14:34:29 up 7 days, 18:51, 1 user, load average: 1.00, 0.95, 0.61
- top:名称
- 14:34:29 :系统当前时间
- up 7 days, 14:30:系统以及运⾏的时间,和 uptime 命令相等
- 1 users:当前有 1 个⽤户在线
- load average: 1.00, 0.95, 0.61:系统负载,即任务队列的平均⻓度。 三个数值分别为 1 分钟、5 分钟、15 分钟前到现在的平均值。
Tasks: 290 total, 2 running, 287 sleeping, 0 stopped, 1 zombie
- Tasks:任务,也就是进程
- 290 total:当前总共有 290 个任务,也就是 290 个进程
- 2 running:2 个进程正在运⾏
- 287 sleeping:263 个进程正在休眠
- 0 stopped:0 个停⽌的进程
- 1 zombie:1 个僵⼫进程
%Cpu(s): 51.0 us, 0.7 sy, 0.0 ni, 47.8 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
- %Cpu(s):CPU 使⽤率
- 51.0 us:⽤户空间占⽤ CPU 时间的百分⽐(⼤部分进程都运⾏在⽤户态,通常都是希望⽤户空间 CPU 越⾼越好)
- 0.7 sy:内核空间占⽤ CPU 时间的百分⽐(Linux 内核态占⽤的 CPU 时间,系统 CPU 占⽤越⾼,表明系统某部分存在瓶颈。通常这个值越低越好)
- 0.0 ni:占⽤ CPU 时间的百分⽐(ni 是 nice 的缩写,进程⽤户态的优先级,如果调整过优先级,那么展示的就是调整过 nice 值的进程消耗掉的 CPU 时间,如果系统中没有进程被调整过 nice 值,那么 ni 就显示为 0)
- 47.8 id:空闲 CPU 占⽤率,等待进程运⾏
- 0.0 wa:等待输⼊输出的 CPU 时间百分⽐(CPU 的处理速度是很快的,磁盘 IO 操作是⾮常慢的。wa 表示 CPU 在等待 IO 操作完成所花费的时间。系统不应该花费⼤量的时间来等待 IO操作,否则就说明 IO 存在瓶颈)
- 0.0 hi:CPU 硬中断时间百分⽐(硬中断是硬盘、⽹卡等硬件设备发送给 CPU 的中断消息 )
- 0.5 si:CPU 软中断时间百分⽐(软中断是由程序发出的中断 )
- 0.0 st:被强制等待(involuntary wait)虚拟 CPU 的时间,此时 Hypervisor 在为另⼀个虚拟处理器服务。
MiB Mem : 3889.9 total, 366.0 free, 1535.2 used, 1988.6 buff/cache
- MiB Mem:内存
- 3889.9 total:物理内存总量
- 366.0 free:空闲内存量
- 1535.2 used:已使⽤的内存量
- 1988.6 buff/cache:⽤作内核缓存的内存量
MiB Swap: 2048.0 total, 2035.2 free, 12.8 used. 2082.9 avail Mem
- MiB Swap:交换空间(虚拟内存,当内存不⾜的时候,把⼀部分硬盘空间虚拟成内存使⽤)
- 2048.0 total:交换区总量
- 2035.2 free:空闲交换区总量
- 12.8 used:使⽤的交换区总量
- 2082.9 avail Mem:可⽤于启动⼀个新应⽤的内存(物理内存),和 free 不同,它计算的是可回收的 page cache 和 memory slab
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- PID:进程 id
- USER:进程所有者
- PR:进程的优先级,越⼩优先级越⾼
- NI:nice 值,负值表示⾼优先级,正值表示低优先级
- VIRT:进程使⽤的虚拟内存,单位是 kb
- RES:进程使⽤的物理内存,单位 kb
- SHR:进程使⽤的共享内存,单位 kb
- S:进程状态(S 表示休眠,R 表示正在运⾏, Z 表示僵死状态,N 表示该进程优先值为负数,I 表示空闲状态)
- %CPU:进程占⽤ CPU 时间的百分⽐
- %MEM:进程占⽤内存的百分⽐
- TIME+:进程实际运⾏的时间
- COMMAND:进程的名称
pstree
显示进程树
kill
kill 命令是⽤于结束进程的命令或者⽤于显示相关信号
kill [选项] [参数]
选项:
- -l : 显示信号名称
- -s : 指定发送的信号
- -a : 杀死进程组中的所有进程
- -p : 杀死进程组中的进程,并将它们从进程组中剔除
- -u : 指定用户
- -signal : 发送指定的信号
参数:
- 进程号: 要结束的进程号
进程的创建
并发和并行
-
并发:多个任务在同⼀时间段被调度运行,⽐如同时有两个任务在运行,这就是并发。在有限的 cpu 核⼼的情况下(如只有⼀个 cpu 核⼼) , 利⽤快速交替 (时间⽚轮
转) 执⾏来达到宏观上的同时执⾏ -
并行:多个任务在不同时间段被调度运行,⽐如同时有两个任务在不同 CPU 上运行,这就是并行。在 cpu 多核的⽀持下,实现物理上的同时执⾏
并⾏是基于硬件完成,⽽并发则可以使⽤软件算法来完成, 在完成任务时,可以创建多个进程并发执⾏
fork()
创建子进程
返回值:
- 0: 子进程
- -1: 出错
创建子进程的过程: - 父进程 fork() 系统调用,创建子进程,返回子进程的进程号
- 子进程复制父进程的地址空间
- 子进程从 fork() 系统调用返回,父进程继续执行
⽗⼦进程并发执⾏, ⼦进程从 fork() 之后开始执⾏
⽗⼦进程的执⾏顺序由操作系统算法决定的,不是由程序本身决定
⼦进程会拷⻉⽗进程地址空间的内容, 包括缓冲区、⽂件描述符等 (COPY ON WRITE)
父子进程执行不同的任务
- 使用 fork() 创建子进程,⽗进程和⼦进程可以并发执⾏不同的任务,
- 执行不同的任务需要利用fork()函数返回值
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{pid_t cpid;cpid = fork();if (cpid == -1){perror("[ERROR] fork()");exit(EXIT_FAILURE);}else if(cpid == 0){// 子进程printf("Child process task.\n");exit(EXIT_SUCCESS);}else if (cpid > 0){// 父进程printf("Parent process task.\n");}//父子进程都要执行的代码printf("Child and Process Process task.\n");
return 0;
}
创建多个进程
- 在创建多个进程时, 最主要的原则为 由⽗进程统⼀创建,统⼀管理, 不能进⾏递归创建
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main(){int cpid;cpid = fork();if (cpid == -1){perror("fork(): ");exit(EXIT_FAILURE);}else if (cpid == 0){// 子进程printf("The child process < %d > running...\n",getpid());sleep(2);printf("The child process < %d > has exited\n",getpid());exit(EXIT_SUCCESS);}else if (cpid > 0){// 父进程cpid = fork();if (cpid == -1){perror("fork(): ");}else if (cpid == 0){printf("The child process < %d > running...\n",getpid());sleep(3);printf("The child process < %d > has exited\n",getpid());exit(EXIT_SUCCESS);}else if (cpid > 0){}}return 0;
}
进程的退出
在进程结束时,需要释放进程地址空间 以及内核中产⽣的各种数据结构
资源的释放需要通过调⽤ exit 函数或者 _exit 函数来完成
在程序结束时,会自动调⽤ exit 函数
exit()和_exit()
exit()函数让当前进程退出,并且刷新缓冲区
#include <stdlib.h>
void exit(int status);
参数:
- status:进程退出状态
- 系统中定义了 EXIT_SUCCESS 和 EXIT_FAILURE 两个宏,用来表示成功和失败的状态码,具体定义在头文件 stdlib.h 中
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
示例:
创建⼀个⼦进程,让⼦进程延时 3 s 后退出
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(){pid_t cpid;
cpid = fork();
if (cpid == -1){
perror("[ERROR] fork(): ");
exit(EXIT_FAILURE);
}else if(cpid == 0){printf("Child Process < %d > running...\n",getpid());
sleep(3);
printf("Child Process < %d > has exited.\n",getpid());
exit(EXIT_SUCCESS);
}else if(cpid > 0){
sleep(5);
}
return 0;
}
_exit()
exit 函数与 _exit 函数功能相似, 但有很多不同, 具体如下:
- _exit() 属于系统调⽤, 能够使进程停⽌运⾏, 并释放空间以及销毁内核中的各种数据结构
- exit() 基于_exit() 函数实现, 属于库函数, 可以清理 I/O 缓冲区
进程的等待
- 在⼦进程运⾏结束后,进⼊僵死状态, 并释放资源, ⼦进程在内核中的 数据结构 依然保留
- ⽗进程 调⽤ wait() 与 waitpid() 函数等待⼦进程退出后,释放⼦进程遗留的资源
task_struct 结构体随着进程的创建而创建和销毁而销毁, 它包含了进程的所有信息, 包括进程号、进程状态、进程调度信息、进程资源使用信息等
wait()函数 和 waitpid()函数
wait()函数
函数头文件
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:
让函数调⽤者进程进⼊到睡眠状态, 等待⼦进程进⼊僵死状态后,释放相关资源并返回
参数:
- wstatus: 指向整数的指针,用来接收⼦进程的退出状态
获取具体值需要使⽤ WEXITSTATUS() 宏定义
返回:
- 若成功,返回值是⼦进程的进程号
- 若出错,返回值是 -1
会阻塞调⽤者进程(⼀般为⽗进程)
在⼦进程状态为僵死态时,回收资源,并释放资源后返回
创建⼀个⼦进程, 延时 3s 后退出, ⽗进程等待⼦进程退出
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{pid_t cpid;cpid = fork();if (cpid == -1){perror("[ERROR] fork(): ");exit(EXIT_FAILURE);}else if(cpid == 0){printf("The Child process < %d > running...\n",getpid());sleep(3);exit(88);}else if(cpid > 0){int rpid,status = 0;rpid = wait(&status);//会阻塞父进程,等待子进程的状态变化,自动释放资源并返回if (rpid == -1){perror("[ERROR] wait() : ");exit(EXIT_FAILURE);}printf("The Child Process < %d > has exited,exit code < %d >.\n",rpid,WEXITSTATUS(status));}return 0;
}
在 wait 存储在 satus 变量的值, 存储了很多信息, 通过⼀系列 W 开头的宏来解析获取
WIFEXITED(status) : 进程是否正常结束
WEXITSTATUS(wstatus) : 获取进程退出状态值, exit 函数的参数
WIFSIGNALED(wstatus) : 表示该⼦进程是否被信号结束的, 返回真,则表示被信号结束的
WTERMSIG(wstatus) : 返回结束该⼦进程的那个信号的信号值
WCOREDUMP(wstatus) : 表示该⼦进程被信号唤醒的
WIFSTOPPED(wstatus) : 表示该⼦进程是否被信号中⽌ (stop) 的 , 返回真,则表示是被信号中⽌的
waitpid()函数
waitpid 函数的功能与 wait 函数⼀样,但⽐ wait() 函数功能更强⼤, waitpid() 函数可以指定等待的进程
####函数头⽂件
#include <sys/types.h>
#include <sys/wait.h>
函数原型
pid_t waitpid(pid_t pid, int *wstatus, int options);
函数参数
pid : 进程 id
- -1 : 可以等待任意⼦进程
- >0 : 等待 id 为 pid 的进程
wstatus : 保存⼦进程退出状态值变量的指针
options : 选项
- WNOHANG : ⾮阻塞选项 // 若没有可等待的进程, 则返回 0, 否则返回 -1
- WUNTRACED : 等待被跟踪的进程
- WCONTINUED : 继续被跟踪的进程
- WEXITED : 等待退出的进程
- WSTOPPED : 等待停止的进程
- WNOWAIT : 不创建新的进程组
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{pid_t cpid;cpid = fork();if (cpid == -1){perror("[ERROR] fork(): ");exit(EXIT_FAILURE);}else if(cpid == 0){printf("The Child process < %d > running...\n",getpid());sleep(3);exit(88);}else if(cpid > 0){int rpid,status = 0;//rpid = waitpid(-1,&status,0);//-1是等待任意子进程退出 // 0是默认阻塞的rpid = waitpid(-1,&status,WNOHANG);//WNOHANG是非阻塞if (rpid == -1){perror("[ERROR] wait() : ");exit(EXIT_FAILURE);}
#if 0//没有子进程退出就返回0while((rpid = waitpid(-1,&status,WNOHANG)) == 0){
}
#endifprintf("The Child Process < %d > has exited,exit code < %d >.\n",rpid,WEXITSTATUS(status));}return 0;
}
进程的替换
创建⼀个进程后,pid 以及在内核中的信息保持 保持不变, 但进程所执⾏的代码进⾏替换
作⽤ : 通过⼀个进程启动另外⼀个进程
应⽤场景:Linux 终端应⽤程序,执⾏命令时,通过创建⼀个进程后,在替换成命令的可执⾏程序再执⾏
在 Linux 系统中提供了⼀组⽤于进程替换的替换,共有 6 个函数
函数原型:
int execl (const char *__path, const char *__arg, ... / (char *) NULL */)> pathname 指向一个字符数组,即字符串。这个字符串表示可执行文件的路径> arg 指向一个字符数组,即命令行参数。这个参数列表可以为空。> 省略号 ... 表示可变参数列表,它允许传递任意数量的参数给可执行文件,包括命令行参数。在参数列表的最后必须以 (char *) NULL 来指示结束。> NULL 是一个字符型指针表示空值,用来指示参数列表的结束。int execlp(const char *file, const char arg, … / (char *) NULL */);int execle(const char *pathname, const char arg, … /, (char *) NULL, char *const envp[] */);int execv(const char *pathname, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[], char *const envp[]);> 函数参数:path:可执文件的路径名file : 可执文件名,可以通过 path 环境变量指定的路径arg : 参数列表,以 NULL 结尾argv[] : 参数数组envp[] : 环境变量数组
> 函数返回值:成功 : 0失败 : -1
示例:通过 execl 函数族执⾏ ls -l 命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{int ret;#if 0ret = execl("/bin/ls","ls","-l",NULL);//替换当前进程,启动ls命令if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);//退出当前进程}
#endifchar *const argv[]={"ls","-l",NULL};//参数列表ret= execv("/bin/ls",argv);//替换当前进程,启动ls命令if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);}//env可以查看环境变量ret= execlp("ls","ls","-l",NULL);//函数会搜索环境变量当作路径if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);}return 0;
}
//这个操作替换了当前进程,启动了另外的程序
//一般是先创建子进程,然后在子进程中调用 execl 函数族,替换子进程
//替换当前进程,启动ls命令if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);//退出当前进程}
#endifchar *const argv[]={"ls","-l",NULL};//参数列表ret= execv("/bin/ls",argv);//替换当前进程,启动ls命令if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);}//env可以查看环境变量ret= execlp("ls","ls","-l",NULL);//函数会搜索环境变量当作路径if (ret == -1){perror("[ERROR] execl(): ");exit(EXIT_FAILURE);}return 0;
}
//这个操作替换了当前进程,启动了另外的程序
//一般是先创建子进程,然后在子进程中调用 execl 函数族,替换子进程
相关文章:

Linux多进程和多线程(一)-进程的概念和创建
进程 进程的概念进程的特点如下进程和程序的区别LINUX进程管理 getpid()getppid() 进程的地址空间虚拟地址和物理地址进程状态管理进程相关命令 ps toppstreekill 进程的创建 并发和并行fork() 父子进程执行不同的任务创建多个进程 进程的退出 exit()和_exit() exit()函数让当…...

熊猫烧香是什么?
熊猫烧香(Worm.WhBoy.cw)是一种由李俊制作的电脑病毒,于2006年底至2007年初在互联网上大规模爆发。这个病毒因其感染后的系统可执行文件图标会变成熊猫举着三根香的模样而得名。熊猫烧香病毒具有自动传播、自动感染硬盘的能力,以及…...
使用Vue3和Tailwind CSS快速搭建响应式布局
### 第一部分:初始化Vue3项目并安装Tailwind CSS 首先,在你的开发环境中打开终端,然后通过Vue CLI来创建一个新的Vue3项目。输入如下命令: vue create my-vue-app 按照提示选择Vue3的相关选项,创建完毕后࿰…...

J019_选择排序
一、排序算法 排序过程和排序原理如下图所示: 二、代码实现 package com.itheima.sort;import java.util.Arrays;public class SelectSort {public static void main(String[] args) {int[] arr {5, 4, 3, 1, 2};//选择排序for (int i 0; i < arr.length - 1…...
【linux】vim的使用
目录 一、Vim的基本模式 二、Vim的常见命令 三、Vim的高级用法 四、Vim的进阶使用技巧 在Linux系统中,Vim是一款功能强大的文本编辑器,特别适用于程序员的代码编辑和修改。以下是Vim的详细使用教程,包括其基本模式、常见命令和高级用法。…...

【工具测评】ONLYOFFICE8.1版本桌面编辑器测评:好用!
随着远程工作的普及和数字化办公的发展,越来越多的人开始寻找功能强大、易于使用的办公软件。在这个背景下,ONLYOFFICE 8.1应运而生,成为许多用户的新选择。ONLYOFFICE 8.1是一款办公套件软件,提供文档处理、电子表格和幻灯片制作…...
核方法总结(四)——高斯过程回归学习笔记
一、定义 基于核方法的线性回归模型和传统线性回归一样,可以用未知数据进行预测,但不能确定 预测的可信度。在参考书第二章中可知,基于贝叶斯方法可以实现对未知数据依概率预测,进而可得到预测的可信度。这一方法中,通…...

【Python3的内置函数和使用方法】
目录 Python 特点 Python 中文编码 Python 变量类型 Python列表 Python 元组 元组是另一个数据类型,类似于 List(列表) Python 字典 Python数据类型转换 Python 运算符 Python算术运算符 Python比较运算符 Python赋值运算符 Pyt…...
递推算法计算信号特征
在线算法(在线计算或递推计算)能够在不存储全部数据的情况下逐步更新信号的特征信息,非常适合资源受限的单片机应用场景。 用途:单片机边采集ADC边计算,最终将采集的信号特征计算结果…...
spring-boot-configuration-processor注释处理器
开源项目SDK:https://github.com/mingyang66/spring-parent 个人文档:https://mingyang66.github.io/raccoon-docs/#/ spring-boot-configuration-processor是springboot提供的一个注释处理器(annotation processor),它用于在编译…...

Python和MATLAB粘性力接触力动态模型半隐式欧拉算法
🎯要点 🎯运动力模型计算制作过程:🖊相机捕捉网球运动图,制定运动数学模型,数值微分运动方程 | 🖊计算运动,欧拉算法离散积分运动,欧拉-克罗默算法微分运动方程 &#…...

webstorm无法识别tsconfig.json引用项目配置文件中的路径别名
问题 vite项目模板中,应用的ts配置内容写在tsconfig.app.json文件中,并在tsconfig.json通过项目引用的方式导入 {"files": [],"references": [{"path": "./tsconfig.app.json"},{"path": "./t…...

qiankun微前端:qiankun+vite+vue3+ts(未完待续..)
目录 什么是微前端 目前现有的微前端 好处 使用 子应用的页面在主应用里显示 什么是微前端 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 我的理解就是将一个大型的前端应用拆分成多个模块,每个微前端模块可以由…...

001:开源交易系统开发实战开篇
本专栏采用融入【主力思维】的方法学,包含数据抓取、特征模型开发、历史验证回归测试、每日动态风险评估管理等技术,较大的增强股票投资胜率,让IT开发者拥有一套属于自己思路的专用交易软件。 先简要介绍系统成功和项目,后续持续…...

Pytorch实战(一):LeNet神经网络
文章目录 一、模型实现1.1数据集的下载1.2加载数据集1.3模型训练1.4模型预测 LeNet神经网络是第一个卷积神经网络(CNN),首次采用了卷积层、池化层这两个全新的神经网络组件,接收灰度图像,并输出其中包含的手写数字&…...

RabbitMq的基础及springAmqp的使用
RabbitMq 官网:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ? mq就是消息队列,消息队列遵循这先入先出原则。一般用来解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用…...

uniapp uniCloud云开发
uniCloud概述 uniCloud 是 DCloud 联合阿里云、腾讯云、支付宝云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。 uniCloud 的 web控制台地址:https://unicloud.dcloud.net.cn 文档:https://doc.dcloud.net.cn/uniCloud/ un…...

智能扫地机,让生活电器更加便民-NV040D扫地机语音方案
一、语音扫地机开发背景: 随着人工智能和物联网技术的飞速发展,智能家居设备已成为现代家庭不可或缺的一部分。其中,扫地机作为家庭清洁的重要工具,更是得到了广泛的关注和应用。 然而,传统的扫地机在功能和使用上仍存…...

【后端面试题】【中间件】【NoSQL】ElasticSearch索引机制和高性能的面试思路
Elasticsearch的索引机制 Elasticsearch使用的是倒排索引,所谓的倒排索引是相对于正排索引而言的。 在一般的文件系统中,索引是文档映射到关键字,而倒排索引则相反,是从关键字映射到文档。 如果没有倒排索引的话,想找…...

【漏洞复现】时空智友ERP updater.uploadStudioFile接口处存在任意文件上传
0x01 产品简介 时空智友ERP是一款基于云计算和大数据技术的企业资源计划管理系统。该系统旨在帮助企业实现数字化转型,提高运营效率、降低成本、增强决策能力和竞争力,时空智友ERP系统涵盖了企业的各个业务领域,包括财务管理、供应链管理、生…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...