Linux | 进程控制(进程终止与进程等待)

文章目录

  • Linux | 进程控制 — 进程终止 & 进程等待
    • 1、进程终止
      • 进程常见退出方法
      • 1.1退出码
        • 基本概念
        • 获取退出码的方式
        • 常见退出码约定
        • 使用场景
      • 1.2 strerror函数 & errno宏
      • 1.3 _exit函数
      • 1.4_exit和exit的区别
        • 1.4.1 所属头文件与函数原型
        • 1.4.2 执行过程差异
        • **结合现象分析**:
    • 2、进程等待
      • 2.1 进程等待的作用
      • 2.2 僵尸进程(Zombie Process)
      • 2.3 `wait()` 系统调用
      • 2.4 `waitpid()` 系统调用
      • 2.5 示例代码
    • 3、进程程序替换
      • 3.1 `exec` 系列函数
        • 3.1.1 `execl()`
        • 3.1.2 `execlp()`
        • 3.1.3 `execle()`
        • 3.1.4 `execv()`
        • 3.1.5 `execvp()`
        • 3.1.6 `execvpe()`
      • 3.2 `exec` 系列函数的特点
      • 3.3 示例代码

Linux | 进程控制 — 进程终止 & 进程等待

1、进程终止

进程常见退出方法

进程退出场景

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

正常终止(可以通过echo $?查看进程退出码)

1.从main返回

2.调用exit

3._exit

异常退出:

  • ctrl + c,信号终止

1.1退出码

在 Linux 系统中,进程的退出码(也称为返回值)是进程结束时返回给其父进程或系统的值,用于表示进程执行的结果。下面从基本概念、获取方式、常见约定、使用场景等方面详细讲解。

基本概念
  • 进程的退出码是一个整数值,范围通常是 0 - 255。在 C 语言编写的程序中,通常通过 main 函数的 return 语句或者 exit() 函数来设置退出码。例如:
#include <stdio.h>
#include <stdlib.h>int main() {// 使用 return 语句设置退出码return 0; // 或者使用 exit() 函数// exit(0); 
}
获取退出码的方式
  • 父进程获取子进程退出码:父进程可以使用 wait()waitpid() 等系统调用获取子进程的退出状态信息,然后通过一些宏来提取退出码。示例如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程return 42;} else if (pid > 0) {// 父进程int status;waitpid(pid, &status, 0);if (WIFEXITED(status)) {int exit_code = WEXITSTATUS(status);printf("子进程退出码: %d\n", exit_code);}}return 0;
}
  • shell 中获取进程退出码:在 shell 里,可以使用 $? 变量获取上一个执行命令的退出码。例如:
./my_program
echo $?
常见退出码约定

虽然 Linux 没有强制统一所有程序使用特定的退出码,但存在一些被广泛遵循的约定:

  • 退出码 0:表示进程正常结束,任务成功完成。这是最常见的退出码,表示程序按预期执行完毕。
  • 退出码 1:一般代表通用的错误,当程序遇到一些未明确分类的错误时,常返回这个退出码。
  • 退出码 2:通常意味着程序在使用命令行参数时出现了错误,例如参数数量不对、参数格式错误等。
  • 退出码 126:表示命令虽然找到了,但由于权限问题或其他原因无法执行。
  • 退出码 127:表明命令未找到,可能是因为命令拼写错误或者该命令不在系统的搜索路径中。
  • 退出码 128 + N:其中 N 是信号编号。当进程因接收到信号而终止时,退出码通常是 128 + 信号编号。例如,进程因接收到 SIGTERM(信号编号 15)而终止,退出码就是 143(128 + 15)。
使用场景
  • 错误处理与调试*:开发人员可以根据退出码快速定位程序出现问题的大致原因。例如,如果程序返回退出码 2,就可以先检查命令行参数的处理逻辑。
  • 脚本流程控制:在 shell 脚本中,根据命令的退出码决定后续的操作。比如,如果某个依赖程序执行失败(返回非零退出码),脚本可以选择终止执行或者尝试其他替代方案。
./dependency_program
if [ $? -ne 0 ]; thenecho "依赖程序执行失败,脚本终止"exit 1
fi
  • 系统监控:系统监控工具可以根据进程的退出码判断进程是否正常运行。如果进程频繁以非零退出码结束,可能表示系统存在潜在问题,需要进一步排查。

1.2 strerror函数 & errno宏

strerror

头文件#include<string.h>

返回值:指向描述error errnum的错误字符串的指针,简单来说可以将退出码和对应的错误对应上。

举例:

#include<string.h>
int main()
{for(int i=0;i<10;i++){printf("%d: %s\n",strerror(i));}return 0;
}

效果如下,后面输出的就是退出码对应的错误描述:

errno

头文件#include<errno.h>

简单的说,errno会返回最后的一次错误码,使用errno可以获得退出码,通过返回退出码,在多进程中也可以让父进程知道子进程的状况。

注意:但是当进程异常退出的时候,本质可能就是代码没有跑完,那么进程的退出码就无意义了,所以应该要先看进程退出的时候,如果要关心进程的推出情况,要先关心退出时后有没有出异常,如果没有异常,再看结果是否正确,然后关心退出码。


  • 父进程关心子进程的退出,只需要确定:
    1. 父进程是否收到来自子进程的信号,若没有,说明没有异常,代码正常跑完
    2. 查看退出结果:0表示成功,非0表示错误,对应各自的原因

举例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>int main()
{int ret = 0;char *p = (char*)malloc(1000*1000*1000*4);if(p==NULL){printf("malloc error, %d: %s\n".errno,strerror(errno));ret = errno;}   else{printf("malloc success\n");}   return ret;
}

1.3 _exit函数

头文件#include<unistd.h>

函数格式void _exit(int status);

exit函数最后也会调用_exit,但是在调用exit之前,还会做以下工作:

1、执行用户通过atexiton_exit定义的清理函数

2、关闭所有打开的流,所有的缓存数据均被写入

3、调用_exit

例1:

int main()
{printf("hello linux\n");exit(12);
}

或者:

int main()
{printf("hello linux\n");return 12;
}

编译执行完后再使用echo $?查询退出码,效果均如下:
在这里插入图片描述

区别在于:exit在任意地方被调用,都表示调用进程直接退出,如果调用的是return,只表示当前函数返回,原进程继续运行,如果调用一个含exit或者return的函数,就可以明显观察到。

1.4_exit和exit的区别

在 Linux 系统中,exit_exit 都用于终止进程,但它们在功能实现、调用过程以及使用场景等方面存在明显区别,下面为你详细介绍:

1.4.1 所属头文件与函数原型
  • exit:它是标准 C 库中的函数,其原型定义在 <stdlib.h> 头文件中,函数原型为 void exit(int status);。这里的 status 是进程的退出状态码,通常 0 表示正常退出,非零表示异常退出。
  • _exit:这是一个系统调用,其原型定义在 <unistd.h> 头文件中,函数原型为 void _exit(int status);status 的含义与 exit 中的相同。

1.4.2 执行过程差异
  • exit

    • 在调用 exit 时,它会先执行一些清理工作。首先,会调用所有通过 atexit 函数注册的清理函数,这些函数可以用于释放资源、关闭文件描述符等操作。
    • 接着,会刷新所有打开的标准 I/O 流缓冲区,将缓冲区中的数据写入对应的文件或设备。
    • 最后,调用 _exit 系统调用来真正终止进程,并将 status 作为退出状态返回给父进程。
  • _exit

    • _exit 是一个底层的系统调用,它会直接终止进程,不会执行任何清理工作。也就是说,它不会调用 atexit 注册的函数,也不会刷新标准 I/O 流缓冲区。
结合现象分析
int main()
{printf("hello world");sleep(1);//使用sleep能够观察到一些现象,下文会提及exit(11);
}

运行完毕后再调用echo $?查看退出码,效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是将exit改为_exit后:

int main()
{printf("hello world");sleep(1);_exit(11);
}

运行完毕后再调用echo $?查看退出码,效果如下:

在这里插入图片描述

原因

当代码中输出的内容以\n结尾时,当代码运行到printf这条语句时,程序会直接输出内容,但是如果没有以\n结尾,那么就会先将内容存到缓冲区中,当程序结束前会冲刷缓冲,关闭流,然后就有打印输出的效果,也正因此会发现运行的时候是先等待了一秒钟,输出句子后程序马上结束,而不是先输出句子,等待一秒钟再结束程序。


结合下图

  • 调用exit()后会先执行用户定义的清理函数,再冲刷缓冲,关闭流等,因此会有打印字符串的效果,最后再调用_exit系统调用
  • _exit()是一个系统调用接口,调用_exit()后,其会在操作系统内部直接终止进程,对应缓冲区的数据不做刷新。

2、进程等待

2.1 进程等待的作用

  • 之前在Linux | 进程状态一文中有提及过僵尸进程的问题,如果子进程退出,父进程没有反应,可能造成僵尸进程的问题,导致内存泄漏
  • 当进程一旦变成僵尸状态,即使使用Kill -9也无法结束进程,需要通过进程等待来结束它,进而解决内存泄漏的问题
  • 需要通过进程等待,获得子进程的退出情况和父进程给子进程分配的任务完成的情况,例如子进程执行程序完毕后结果是否正确,或者是否正常退出
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。

在Linux中,进程等待是指一个进程(通常是父进程)等待其子进程终止并获取其退出状态。这是通过系统调用 wait()waitpid() 来实现的。进程等待的主要目的是防止子进程成为“僵尸进程”(Zombie Process),并确保父进程能够获取子进程的退出状态。

2.2 僵尸进程(Zombie Process)

当一个子进程终止时,它的退出状态需要被父进程读取。如果父进程没有读取子进程的退出状态,子进程的进程描述符仍然保留在系统中,这种进程称为“僵尸进程”。僵尸进程不占用CPU资源,但会占用进程表中的条目,如果系统中存在大量僵尸进程,可能会导致进程表耗尽,无法创建新的进程。

2.3 wait() 系统调用

wait() 系统调用会使父进程阻塞,直到它的任意一个子进程终止。如果已经有子进程终止,wait() 会立即返回。

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
  • 参数:

    • status: 一个指向整数的指针,用于存储子进程的退出状态。可以通过宏(如 WIFEXITED(status)WEXITSTATUS(status) 等)来解析这个状态。
  • 返回值:

    • 成功时返回终止的子进程的PID。
    • 如果没有子进程,返回-1,并设置 errnoECHILD

2.4 waitpid() 系统调用

waitpid() 提供了比 wait() 更灵活的控制,允许父进程等待特定的子进程,并且可以指定是否阻塞。

#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
  • 参数:

    • pid: 指定要等待的子进程的PID。
      • pid > 0: 等待进程ID等于 pid 的子进程。
      • pid = -1: 等待任意子进程,与 wait() 类似。
      • pid = 0: 等待与调用进程属于同一个进程组的任意子进程。
      • pid < -1: 等待进程组ID等于 pid 绝对值的任意子进程。
    • status: 与 wait() 中的 status 参数相同,用于存储子进程的退出状态。
    • options: 控制 waitpid() 的行为,常用的选项有:
      • WNOHANG: 如果没有子进程退出,立即返回,不阻塞。
      • WUNTRACED: 如果子进程被暂停(例如通过 SIGSTOP 信号),也返回。
  • 返回值:

    • 成功时返回终止的子进程的PID。
    • 如果指定了 WNOHANG 且没有子进程退出,返回0。
    • 如果出错,返回-1,并设置 errno

2.5 示例代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");exit(1);} else if (pid == 0) {// 子进程printf("Child process is running\n");sleep(2);printf("Child process is exiting\n");exit(42);} else {// 父进程int status;printf("Parent process is waiting for child\n");wait(&status);if (WIFEXITED(status)) {printf("Child exited with status %d\n", WEXITSTATUS(status));} else {printf("Child did not exit normally\n");}}return 0;
}

3、进程程序替换

在Linux中,进程程序替换是指将一个进程当前执行的程序替换为另一个全新的程序。这个过程是通过 exec 系列函数来实现的。进程程序替换后,进程的PID、父进程、文件描述符等信息保持不变,但进程的代码段、数据段、堆栈等会被新程序的内容替换。

exec 系列函数是Linux系统调用的一部分,它们的作用是加载并执行一个新的程序,替换当前进程的地址空间。执行成功后,原程序的代码将不再运行,而是由新程序从头开始执行。


3.1 exec 系列函数

exec 系列函数有多个变体,它们的核心功能相同,但在参数传递方式和行为上略有不同。exec系列函数只有失败返回值(-1),没有成功返回值

以下是常用的 exec 函数:

3.1.1 execl()
int execl(const char *path, const char *arg, ..., (char *) NULL);
  • 功能: 加载并执行指定路径的程序。

  • 参数:

    • path: 要执行的程序的完整路径。
    • arg: 程序的命令行参数,第一个参数通常是程序名,最后一个参数必须是 NULL
  • 示例:

    execl("/bin/ls", "ls", "-l", NULL);
    

    这行代码会执行 /bin/ls 程序,并传递 -l 参数。


3.1.2 execlp()
int execlp(const char *file, const char *arg, ..., (char *) NULL);
  • 功能: 类似于 execl(),但会在 PATH 环境变量中查找可执行文件。
  • 参数:
    • file: 要执行的程序名(不需要完整路径)。
    • arg: 程序的命令行参数,最后一个参数必须是 NULL
  • 示例:
    execlp("ls", "ls", "-l", NULL);
    
    这行代码会在 PATH 中查找 ls 并执行。

3.1.3 execle()
int execle(const char *path, const char *arg, ..., (char *) NULL, char *const envp[]);
  • 功能: 加载并执行指定路径的程序,并允许指定环境变量。
  • 参数:
    • path: 要执行的程序的完整路径。
    • arg: 程序的命令行参数,最后一个参数必须是 NULL
    • envp: 自定义的环境变量数组,必须以 NULL 结尾。
  • 示例:
    char *envp[] = {"USER=test", "PATH=/bin", NULL};
    execle("/bin/ls", "ls", "-l", NULL, envp);
    

3.1.4 execv()
int execv(const char *path, char *const argv[]);
  • 功能: 加载并执行指定路径的程序,参数通过数组传递。
  • 参数:
    • path: 要执行的程序的完整路径。
    • argv: 命令行参数数组,必须以 NULL 结尾。
  • 示例:
    char *argv[] = {"ls", "-l", NULL};
    execv("/bin/ls", argv);
    

3.1.5 execvp()
int execvp(const char *file, char *const argv[]);
  • 功能: 类似于 execv(),但会在 PATH 环境变量中查找可执行文件。
  • 参数:
    • file: 要执行的程序名(不需要完整路径)。
    • argv: 命令行参数数组,必须以 NULL 结尾。
  • 示例:
    char *argv[] = {"ls", "-l", NULL};
    execvp("ls", argv);
    

3.1.6 execvpe()
int execvpe(const char *file, char *const argv[], char *const envp[]);
  • 功能: 类似于 execvp(),但允许指定环境变量。
  • 参数:
    • file: 要执行的程序名(不需要完整路径)。
    • argv: 命令行参数数组,必须以 NULL 结尾。
    • envp: 自定义的环境变量数组,必须以 NULL 结尾。
  • 示例:
    char *argv[] = {"ls", "-l", NULL};
    char *envp[] = {"USER=test", "PATH=/bin", NULL};
    execvpe("ls", argv, envp);
    

3.2 exec 系列函数的特点

  1. 替换当前进程:

    • exec 系列函数会用新程序替换当前进程的地址空间,包括代码段、数据段、堆栈等。
    • 进程的PID、父进程、文件描述符等信息保持不变。
  2. 不创建新进程:

    • exec 不会创建新进程,它只是替换当前进程的内容。
  3. 成功时不返回:

    • 如果 exec 执行成功,它不会返回,因为原程序的代码已经被替换。
    • 如果 exec 失败,它会返回 -1,并设置 errno
  4. 文件描述符的继承:

    • 默认情况下,exec 会保留进程打开的文件描述符(除非显式设置 FD_CLOEXEC 标志)。

3.3 示例代码

  • 实例1:

​ 以下是一个完整的示例,展示如何使用 fork()exec() 创建子进程并替换程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");exit(1);} else if (pid == 0) // 子进程{printf("子进程正在执行\n");// 替换为 ls 程序char *argv[] = {"ls", "-l", NULL};execvp("ls", argv);//如果进程替换成功,则下面的代码不会执行,如果进程替换失败(例如命令错误、路径错误等原因导致错误),则会执行下面的语句perror("hello world\n");exit(1);} else // 父进程{int status;wait(&status); // 等待子进程结束printf("父进程检测到子进程退出\n");}return 0;
}

程序运行结果:
在这里插入图片描述

  • 实例2:

    test1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/types.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");exit(1);}   else if (pid == 0) // 子进程{   printf("子进程正在执行\n");// 替换为 ls 程序//char *argv[] = {"ls", "-l", NULL};//execvp("ls", argv);//execl("/usr/bin/ls","/usr/bin/ls","-ln","-a",NULL);execl("./test2","test2",NULL);//如果进程替换成功,则下面的代码不会执行perror("hello world\n");exit(1);}   else // 父进程{   int status;wait(&status); // 等待子进程结束printf("父进程检测到子进程退出\n");}   return 0;
}

test2.c

#include<stdio.h>int main(){printf("这是test2\n");return 0;
}

将test1.c编译成可执行文件后,执行结果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/71464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android - Handler使用post之后,Runnable没有执行

问题&#xff1a;子线程创建的Handler。如果 post 之后&#xff0c;在Handler.removeCallbacks(run)移除了&#xff0c;下次再使用Handler.postDelayed(Runnable)接口或者使用post时&#xff0c;Runnable是没有执行。导致没有收到消息。 解决办法&#xff1a;只有主线程创建的…

鱼皮面试鸭30天后端面试营

day1 1. MySQL的索引类型有哪些? MySQL里的索引就像是书的目录&#xff0c;能帮数据库快速找到你要的数据。以下是各种索引类型的通俗解释&#xff1a; 按数据结构分 B树索引&#xff1a;最常用的一种&#xff0c;数据像在一棵树上分层存放&#xff0c;能快速定位范围数据…

【核心算法篇十二】《深入解剖DeepSeek多任务学习:共享表示层的24个设计细节与实战密码 》

引言:为什么你的模型总在"精神分裂"? 想象你训练了一个AI实习生: 早上做文本分类时准确率90%下午做实体识别却把"苹果"都识别成水果公司晚上做情感分析突然开始输出乱码这就是典型的任务冲突灾难——模型像被不同任务"五马分尸"。DeepSeek通…

DeepSeek应用——与PyCharm的配套使用

目录 一、配置方法 二、使用方法 三、注意事项 1、插件市场无continue插件 2、无结果返回&#xff0c;且在本地模型报错 记录自己学习应用DeepSeek的过程&#xff0c;使用的是自己电脑本地部署的私有化蒸馏模型...... &#xff08;举一反三&#xff0c;这个不单单是可以用…

2025最新智能优化算法:改进型雪雁算法(Improved Snow Geese Algorithm, ISGA)求解23个经典函数测试集,MATLAB

一、改进型雪雁算法 雪雁算法&#xff08;Snow Geese Algorithm&#xff0c;SGA&#xff09;是2024年提出的一种新型元启发式算法&#xff0c;其灵感来源于雪雁的迁徙行为&#xff0c;特别是它们在迁徙过程中形成的独特“人字形”和“直线”飞行模式。该算法通过模拟雪雁的飞行…

vscode通过ssh连接服务器实现免密登录+删除

文章目录 参考&#xff1a; 1、 vscode通过ssh连接服务器实现免密登录删除&#xff08;吐血总结&#xff09;

MySQL 主从复制原理及其工作过程

一、MySQL主从复制原理 MySQL 主从复制是一种将数据从一个 MySQL 数据库服务器&#xff08;主服务器&#xff0c;Master&#xff09;复制到一个或多个 MySQL 数据库服务器&#xff08;从服务器&#xff0c;Slave&#xff09;的技术。以下简述其原理&#xff0c;主要包含三个核…

【赵渝强老师】Spark RDD的缓存机制

Spark RDD通过persist方法或cache方法可以将计算结果的缓存&#xff0c;但是并不是这两个方法被调用时立即缓存&#xff0c;而是触发后面的action时&#xff0c;该RDD才会被缓存在计算节点的内存中并供后面重用。下面是persist方法或cache方法的函数定义&#xff1a; def pers…

设计模式相关知识点

目录 设计模式 设计模式 代码设计原则 设计模式 设计模式 干掉if...else&#xff0c;最好用的3种设计模式&#xff01; | 小傅哥 bugstack 虫洞栈 代码设计原则-CSDN博客 23种设计模式-CSDN博客 策略模式&#xff08;Strategy Pattern&#xff09;-CSDN博客 责任链模式…

ShenNiusModularity项目源码学习(9:项目结构)

ShenNiusModularity源码主要有11个project&#xff08;其实还有officialweb、test两个文件夹&#xff0c;大致有4、5个project&#xff0c;但看着跟主要项目代码没太大关系&#xff0c;暂时不管&#xff09;&#xff0c;这11个project的依赖关系如下图所示&#xff0c;其中最下…

ubuntu22.4搭建单节点es8.1

下载对应的包 elasticsearch-8.1.1-linux-x86_64.tar.gz 创建es租户 groupadd elasticsearc useradd elasticsearch -g elasticsearch -p elasticsearch chmod uw /etc/sudoers chmod -R elasticsearch:elasticsearch elasticsearch 修改配置文件 vim /etc/sysctl.conf vm…

Docker 部署 ollama + DeepSeek

拉取并运行 Ollama Docker 镜像 使用以下命令从 Docker Hub 拉取 Ollama 镜像并运行容器&#xff1a; docker run -d -p 11434:11434 --name ollama ollama/ollama -d&#xff1a;以守护进程模式运行容器&#xff0c;即让容器在后台运行。-p 11434:11434&#xff1a;将容器内…

解决DeepSeek服务器繁忙的有效方法

全球42%的企业遭遇过AI工具服务器过载导致内容生产中断&#xff08;数据来源&#xff1a;Gartner 2025&#xff09;。当竞品在凌晨3点自动发布「智能家居安装指南」时&#xff0c;你的团队可能正因DeepSeek服务器繁忙错失「净水器保养教程」的流量黄金期⏳。147SEO智能调度系统…

Discuz! X3.5 根目录权限设置

在 Discuz! X3.5 中,根目录的权限设置是确保网站安全性和功能正常运行的关键。如果权限设置不当,可能会导致文件无法访问、安全问题(如文件被篡改)或功能异常。以下是关于 Discuz! X3.5 根目录权限设置的详细说明和建议: 1. 根目录位置 Discuz! X3.5 的根目录通常是网站的…

【C++八股】内存对⻬

内存对齐是指编译器按照特定规则安排数据在内存中的存储位置&#xff0c;以提高程序的执行效率和可移植性。 内存对齐的原因&#xff1a; 1. 性能优化&#xff1a; 现代处理器通常要求数据在内存中按照特定的边界对齐&#xff0c;以提高内存访问效率。 如果数据未对齐&#x…

【有啥问啥】DeepSeek 技术原理详解

DeepSeek 技术原理详解 DeepSeek 是一款具有突破性技术的大型语言模型&#xff0c;其背后的技术原理涵盖了多个方面&#xff0c;以下是对其主要技术原理的详细介绍&#xff1a; 架构创新 多头潜在注意力机制&#xff08;MLA&#xff09; 传送门链接: DeepSeek V3中的Multi-…

ML.NET库学习008:使用ML.NET进行心脏疾病预测模型开发

文章目录 ML.NET库学习008&#xff1a;使用ML.NET进行心脏疾病预测模型开发1. 项目主要目的和原理2. 项目概述实现的主要功能&#xff1a;主要流程步骤&#xff1a;关键技术&#xff1a; 3. 主要功能和步骤数据加载与路径处理模型训练与评估模型保存与加载 4. 代码中的数据结构…

FFmpeg 全面知识大纲梳理

1. FFmpeg 简介 FFmpeg 是什么: 一个开源的多媒体处理框架,用于处理音频、视频和流媒体。支持多种格式和编解码器。提供命令行工具和库(如 libavcodec, libavformat, libavfilter 等)。主要功能: 格式转换编解码流媒体处理音视频剪辑、合并、分离添加滤镜、特效压缩与优化…

人工智能基础之数学基础:01高等数学基础

函数 极限 按照一定次数排列的一列数:“&#xff0c;“,…,"…&#xff0c;其中u 叫做通项。 对于数列{Un}如果当n无限增大时&#xff0c;其通项无限接近于一个常数A&#xff0c;则称该数列以A为极限或称数列收敛于A&#xff0c;否则称数列为发散&#xff0c; 极限值 左…

从零搭建微服务项目Base(第5章——SpringBoot项目LogBack日志配置+Feign使用)

前言&#xff1a; 本章主要在原有项目上添加了日志配置&#xff0c;对SpringBoot默认的logback的配置进行了自定义修改&#xff0c;并详细阐述了xml文件配置要点&#xff08;只对日志配置感兴趣的小伙伴可选择直接跳到第三节&#xff09;&#xff0c;并使用Feign代替原有RestT…