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

Linux应用:进程的回收

进程的诞生和消亡

程的诞生通常是通过系统调用(如fork、exec等)来创建新进程。当一个进程完成其任务或者出现错误时,它会进入消亡阶段。进程可以通过exit函数主动结束自身,也可能由于操作系统的调度策略(如资源耗尽、进程异常终止等)而被强制终止。进程结束后,操作系统会回收其占用的资源,如内存、文件描述符等。

进程的诞生

进程0

在操作系统启动过程中,进程 0 是最早被创建的进程,它是整个进程体系的始祖。进程 0 通常由操作系统内核直接初始化,承担着至关重要的任务,例如初始化系统关键数据结构、创建进程 1 等后续进程的基础环境搭建。它运行在内核态,拥有最高的权限,可以直接访问系统硬件资源,对系统的稳定运行起着决定性作用。在类 Unix 系统中,进程 0 也被称为 “swapper” 进程,其主要职责之一是负责进程调度的初始化,为后续进程能够在合适的时机获得 CPU 资源执行奠定基础。

进程1


进程 1 是进程 0 创建的第一个用户态进程,也被称作 “init” 进程。它是所有用户进程的祖先,在系统启动流程中,当内核完成自身初始化以及进程 0 的相关设置后,就会通过特定机制创建进程 1。进程 1 会读取系统配置文件,启动各种系统服务,比如网络服务、文件系统服务等。它负责管理系统中所有用户进程的生命周期,当某个用户进程异常终止时,进程 1 会回收其资源,避免资源泄漏。并且,进程 1 始终存在于系统中,直到系统关闭,是维持系统正常运行的核心进程之一。

fork

fork是 Unix 和类 Unix 系统中用于创建新进程的系统调用。当一个进程调用fork时,内核会为新进程分配独立的进程控制块(PCB),并复制调用进程(父进程)的大部分资源,包括内存空间(数据段、代码段、堆栈段等)、打开的文件描述符、信号处理函数等。新创建的进程(子进程)几乎与父进程一模一样,fork调用会在父进程和子进程中分别返回,在父进程中返回子进程的进程 ID(PID),而在子进程中返回 0。通过这种返回值的差异,程序可以区分当前是在父进程还是子进程中执行不同的逻辑。例如,父进程可能继续执行一些管理任务,而子进程可以执行特定的计算任务或启动新的程序。不过,由于资源复制操作,fork在创建进程时开销相对较大。
父进程可以有多个子进程。在操作系统中,父进程可以通过多次调用 fork 函数来创建多个子进程。每个子进程都是父进程的一个副本,它们可以独立执行不同的任务,并且父进程可以通过各种方式管理和与这些子进程进行交互。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main() {pid_t pid1, pid2;// 创建第一个子进程pid1 = fork();if (pid1 < 0) {// 处理fork失败的情况perror("fork1");return 1;} else if (pid1 == 0) {// 第一个子进程的代码printf("我是第一个子进程,我的PID是 %d,父进程的PID是 %d\n", getpid(), getppid());// 子进程执行一些任务,这里简单地休眠2秒sleep(2);// 子进程退出exit(0);} else {// 父进程继续执行,创建第二个子进程pid2 = fork();if (pid2 < 0) {// 处理fork失败的情况perror("fork2");return 1;} else if (pid2 == 0) {// 第二个子进程的代码printf("我是第二个子进程,我的PID是 %d,父进程的PID是 %d\n", getpid(), getppid());// 子进程执行一些任务,这里简单地休眠3秒sleep(3);// 子进程退出exit(0);} else {// 父进程的代码printf("我是父进程,我的PID是 %d\n", getpid());// 父进程可以等待子进程结束,或者执行其他任务// 这里简单地等待一段时间sleep(5);printf("两个子进程都已结束,父进程继续执行其他任务...\n");}}return 0;
}

在这里插入图片描述

vfork

vfork也是用于创建新进程的系统调用,与fork有相似之处,但也存在显著差异。vfork创建子进程时,子进程与父进程共享内存空间,而不是像fork那样复制内存。这使得vfork创建进程的速度更快,开销更小。在vfork调用后,子进程会先运行,父进程会被阻塞,直到子进程调用exec系列函数(用于执行新的程序)或者exit退出。这种机制确保了子进程在使用共享内存时不会与父进程产生冲突。通常在需要快速创建进程并立即执行新程序的场景中,vfork会比fork更合适。例如,当一个进程需要频繁启动其他程序时,使用vfork可以减少资源开销,提高系统效率。​

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>int main() {pid_t pid;// 使用 vfork() 创建新进程pid = vfork();if (pid < 0) {// vfork() 失败std::cerr << "vfork() failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程std::cout << "This is the child process. PID: " << getpid() << std::endl;// 子进程可以执行一些操作,这里简单地调用 exit()exit(0);} else {// 父进程int status;// 等待子进程结束waitpid(pid, &status, 0);std::cout << "This is the parent process. PID: " << getpid() << std::endl;std::cout << "Child process exited with status: " << WEXITSTATUS(status) << std::endl;}return 0;
}

包含必要的头文件:
:用于输入输出操作。
<unistd.h>:包含 vfork()、getpid() 等系统调用。
<sys/types.h>:包含一些基本的系统数据类型。
<sys/wait.h>:包含 waitpid() 函数。
:包含 exit() 函数。
使用 vfork() 创建新进程:
pid = vfork();:调用 vfork() 函数创建新进程。如果成功,父进程会返回子进程的 PID(大于 0),子进程会返回 0;如果失败,返回 -1。
错误处理:
if (pid < 0):如果 vfork() 失败,输出错误信息并返回 1。
子进程处理:
else if (pid == 0):子进程执行的代码。输出子进程的 PID,然后调用 exit(0) 结束子进程。
父进程处理:
else:父进程执行的代码。使用 waitpid() 等待子进程结束,并获取子进程的退出状态。输出父进程的 PID 和子进程的退出状态。
在这里插入图片描述

僵尸进程

当子进程先于父进程结束,且父进程没有及时调用wait系列函数来获取子进程的退出状态时,子进程就会成为僵尸进程。僵尸进程虽然已经结束运行,但它在系统中仍然占据一定的资源(如进程表项),直到父进程调用wait函数回收其资源。过多的僵尸进程可能会导致系统资源浪费,影响系统性能。

SIGCHILD 信号讲解

  1. 信号概述
    在 Unix 或类 Unix 系统中,信号是一种软件中断机制,用于通知进程发生了某个特定事件。SIGCHILD 信号就是其中之一,它是由内核在以下几种情况下发送给父进程的:
    子进程终止(正常退出或被信号终止)。
    子进程停止(例如通过 SIGSTOP 信号)。
    停止的子进程恢复执行(例如通过 SIGCONT 信号)。
  2. 信号处理的意义
    父进程接收到 SIGCHILD 信号后,通常需要对其进行处理,以避免产生僵尸进程。僵尸进程是指子进程已经终止,但父进程尚未回收其资源(主要是进程表项)的进程。通过处理 SIGCHILD 信号,父进程可以及时回收子进程的资源,释放系统资源。
  3. 信号处理方式
    父进程可以通过以下几种方式处理 SIGCHILD 信号:
    忽略信号:将信号处理函数设置为 SIG_IGN,这样内核会自动回收子进程的资源,避免产生僵尸进程。但这种方式在某些情况下可能会导致一些问题,例如在多线程程序中。
    自定义信号处理函数:父进程可以定义自己的信号处理函数,在函数中调用 wait 或 waitpid 函数来回收子进程的资源。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main() {// 忽略 SIGCHILD 信号signal(SIGCHLD, SIG_IGN);pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程printf("子进程开始执行,PID: %d\n", getpid());sleep(2);printf("子进程结束\n");exit(0);} else {// 父进程printf("父进程继续执行,子进程 PID: %d\n", pid);sleep(5);printf("父进程结束\n");}return 0;
}

signal(SIGCHLD, SIG_IGN);:将 SIGCHILD 信号的处理方式设置为忽略。这样,当子进程终止时,内核会自动回收其资源,不会产生僵尸进程。
子进程打印信息,睡眠 2 秒后退出。
父进程打印信息,睡眠 5 秒后结束。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>// 自定义信号处理函数
void sigchld_handler(int signo) {pid_t pid;int status;// 使用 waitpid 以非阻塞模式回收所有终止的子进程while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {if (WIFEXITED(status)) {printf("子进程 %d 正常结束,退出状态码: %d\n", pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("子进程 %d 被信号 %d 终止\n", pid, WTERMSIG(status));}}
}int main() {// 注册信号处理函数signal(SIGCHLD, sigchld_handler);pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程printf("子进程开始执行,PID: %d\n", getpid());sleep(2);printf("子进程结束\n");exit(10);} else {// 父进程printf("父进程继续执行,子进程 PID: %d\n", pid);sleep(5);printf("父进程结束\n");}return 0;
}

sigchld_handler 函数是自定义的信号处理函数,当父进程接收到 SIGCHILD 信号时会调用该函数。
在 sigchld_handler 函数中,使用 waitpid(-1, &status, WNOHANG) 以非阻塞模式回收所有终止的子进程,并根据子进程的退出状态进行相应的输出。
signal(SIGCHLD, sigchld_handler);:将 SIGCHILD 信号的处理方式设置为自定义的信号处理函数。
子进程打印信息,睡眠 2 秒后以状态码 10 退出。
父进程打印信息,睡眠 5 秒后结束。

父进程wait回

收子进程
wait函数是父进程用于等待子进程结束并获取其退出状态的系统调用。当父进程调用wait时,它会阻塞自己,直到有一个子进程结束。wait函数返回子进程的 PID,并通过参数获取子进程的退出状态,这样父进程就可以对结束的子进程进行善后处理,避免产生僵尸进程。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid;int status;// 创建子进程pid = fork();if (pid < 0) {// 处理 fork 失败的情况perror("fork");return 1;} else if (pid == 0) {// 子进程代码printf("子进程开始执行,PID: %d\n", getpid());sleep(2);  // 模拟子进程执行一段时间printf("子进程结束\n");exit(10);  // 子进程退出,返回状态码 10} else {// 父进程代码printf("父进程等待子进程结束,子进程 PID: %d\n", pid);// 调用 wait 函数等待子进程结束pid_t terminated_pid = wait(&status);if (terminated_pid > 0) {if (WIFEXITED(status)) {// 子进程正常退出printf("子进程 %d 正常结束,退出状态码: %d\n", terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {// 子进程被信号终止printf("子进程 %d 被信号 %d 终止\n", terminated_pid, WTERMSIG(status));}}}return 0;
}

wait 函数示例
创建子进程:使用 fork 函数创建一个子进程。
子进程:打印信息,睡眠 2 秒,然后以状态码 10 退出。
父进程:调用 wait 函数等待子进程结束。wait 函数会阻塞父进程,直到有一个子进程结束。获取子进程的退出状态后,根据状态判断子进程是正常退出还是被信号终止
在这里插入图片描述
WIFEXITED(status):这个宏用于判断子进程是否是正常终止的。所谓正常终止,指的是子进程通过 return 语句、exit 函数或者 _exit 函数退出。如果子进程是正常终止的,该宏返回非零值;否则返回 0。
WIFSIGNALED(status):此宏用于判断子进程是否是非正常终止的,也就是子进程是否是被某个信号所终止的。如果子进程是被信号终止的,该宏返回非零值;否则返回 0。
WEXITSTATUS(status):当子进程正常终止时,使用这个宏可以获取子进程的返回值。需要注意的是,只有在 WIFEXITED(status) 返回非零值时,使用这个宏才有意义。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>int main() {pid_t pid;int status;// 创建子进程pid = fork();if (pid < 0) {// 处理 fork 失败的情况perror("fork");return 1;} else if (pid == 0) {// 子进程代码printf("子进程开始执行,PID: %d\n", getpid());// 模拟子进程执行一段时间sleep(2);// 子进程正常退出,返回状态码 42exit(42);} else {// 父进程代码printf("父进程等待子进程结束,子进程 PID: %d\n", pid);// 调用 wait 函数等待子进程结束pid_t terminated_pid = wait(&status);if (terminated_pid > 0) {if (WIFEXITED(status)) {// 子进程正常退出printf("子进程 %d 正常结束,退出状态码: %d\n", terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {// 子进程被信号终止printf("子进程 %d 被信号 %d 终止\n", terminated_pid, WTERMSIG(status));}}}return 0;
}

创建子进程:
使用 fork() 函数创建一个子进程。fork() 函数会返回两次,在父进程中返回子进程的 PID,在子进程中返回 0,如果创建失败则返回 -1。
子进程部分:
子进程打印自身的 PID 信息,然后调用 sleep(2) 模拟执行一段时间。
最后调用 exit(42) 正常退出,并返回状态码 42。
父进程部分:
父进程打印等待子进程结束的信息,然后调用 wait(&status) 函数等待子进程结束。wait 函数会阻塞父进程,直到有一个子进程结束,并将子进程的退出状态存储在 status 变量中。
父进程通过 WIFEXITED(status) 宏判断子进程是否正常退出。由于子进程是通过 exit(42) 正常退出的,所以该宏返回非零值。
在 WIFEXITED(status) 为真的情况下,使用 WEXITSTATUS(status) 宏获取子进程的退出状态码,并将其打印输出。
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>int main() {pid_t pid;int status;// 创建子进程pid = fork();if (pid < 0) {// 处理 fork 失败的情况perror("fork");return 1;} else if (pid == 0) {// 子进程代码printf("子进程开始执行,PID: %d\n", getpid());// 模拟子进程执行一段时间sleep(2);// 子进程给自己发送 SIGTERM 信号,模拟被信号终止kill(getpid(), SIGTERM);} else {// 父进程代码printf("父进程等待子进程结束,子进程 PID: %d\n", pid);// 调用 wait 函数等待子进程结束pid_t terminated_pid = wait(&status);if (terminated_pid > 0) {if (WIFEXITED(status)) {// 子进程正常退出printf("子进程 %d 正常结束,退出状态码: %d\n", terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {// 子进程被信号终止printf("子进程 %d 被信号 %d 终止\n", terminated_pid, WTERMSIG(status));}}}return 0;
}

子进程在执行一段时间后,调用 kill(getpid(), SIGTERM) 给自己发送 SIGTERM 信号,模拟被信号终止的情况。父进程在子进程结束后,通过 WIFSIGNALED(status) 宏判断子进程是否是被信号终止的,如果是,则使用 WTERMSIG(status) 宏获取终止子进程的信号编号并打印输出。
在这里插入图片描述

waitpid介绍

waitpid函数也是用于等待子进程结束的系统调用,它比wait函数更加灵活。waitpid可以指定等待特定 PID 的子进程,也可以设置非阻塞等待模式或者阻塞模式。通过waitpid,父进程可以更精确地控制对子进程的等待和资源回收操作,例如可以在不阻塞父进程的情况下,定期检查子进程是否结束。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid;int status;// 创建子进程pid = fork();if (pid < 0) {// 处理 fork 失败的情况perror("fork");return 1;} else if (pid == 0) {// 子进程代码printf("子进程开始执行,PID: %d\n", getpid());sleep(2);  // 模拟子进程执行一段时间printf("子进程结束\n");exit(20);  // 子进程退出,返回状态码 20} else {// 父进程代码printf("父进程等待子进程结束,子进程 PID: %d\n", pid);pid_t terminated_pid;// 使用 waitpid 函数以非阻塞模式等待子进程结束while ((terminated_pid = waitpid(pid, &status, WNOHANG)) == 0) {printf("子进程还在运行,父进程继续执行其他任务...\n");sleep(1);}if (terminated_pid > 0) {if (WIFEXITED(status)) {// 子进程正常退出printf("子进程 %d 正常结束,退出状态码: %d\n", terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {// 子进程被信号终止printf("子进程 %d 被信号 %d 终止\n", terminated_pid, WTERMSIG(status));}} else if (terminated_pid == -1) {perror("waitpid");}}return 0;
}

创建子进程:同样使用 fork 函数创建一个子进程。
子进程:打印信息,睡眠 2 秒,然后以状态码 20 退出。
父进程:使用 waitpid 函数以非阻塞模式(WNOHANG)等待子进程结束。在子进程未结束时,父进程可以继续执行其他任务。当子进程结束后,获取其退出状态并进行相应处理。
在这里插入图片描述

竟态初步引入

竞态条件是指当多个进程或线程并发访问共享资源时,由于它们的执行顺序不确定,导致最终结果依赖于它们实际执行顺序的一种现象。在进程编程中,如果多个进程同时对共享资源(如共享内存、文件等)进行读写操作,而没有采取适当的同步机制,就可能出现竞态条件,导致程序运行结果错误。

相关文章:

Linux应用:进程的回收

进程的诞生和消亡 程的诞生通常是通过系统调用&#xff08;如fork、exec等&#xff09;来创建新进程。当一个进程完成其任务或者出现错误时&#xff0c;它会进入消亡阶段。进程可以通过exit函数主动结束自身&#xff0c;也可能由于操作系统的调度策略&#xff08;如资源耗尽、…...

如何利用 AI 技术快速定位和修复生产环境问题

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…...

Linux find 命令完全指南

find 是 Linux 系统最强大的文件搜索工具&#xff0c;支持 嵌套遍历、条件筛选、执行动作。以下通过场景分类解析核心用法&#xff0c;涵盖高效搜索、文件管理及高级技巧&#xff1a; 一、基础搜索模式 1. 按文件名搜索&#xff08;精确/模糊匹配&#xff09; <BASH> f…...

市场波动中的风险管理与策略优化

市场波动中的风险管理与策略优化 在市场交易中&#xff0c;价格的波动性为投资者提供了交易机会&#xff0c;但同时也带来了风险。如何在市场不确定性中进行有效的风险管理&#xff0c;并优化交易策略&#xff0c;是每位交易者都需要思考的问题。本文将探讨市场波动的影响因素、…...

(链表)206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&am…...

Jetson Orin NX jupyter lab的安装和使用

主要是为了梳理一下整个过程&#xff0c;其实步骤很简单&#xff0c;但容易出错。 注意&#xff0c;实际只有两个文件需要写入&#xff0c;一个是jupyter_lab_config.py&#xff0c;一个是jupyter.service。 配置文件的名字要写对&#xff0c;如果总是copy网上的代码&#xff0…...

前端npm包- CropperJS

文章目录 一、CropperJS**核心特性****官网与文档****安装与使用**1. **通过 npm/yarn/pnpm 安装**2. **HTML 结构**3. **引入 CSS 和 JS**4. **初始化裁剪器** **相关插件/替代方案****适用场景****注意事项** 总结 一、CropperJS cropperjs 是一个轻量级、功能强大的 图片裁…...

农业建设项目管理系统评测:8款推荐工具优缺点分析

本文主要介绍了以下8款农业建设项目管理系统&#xff1a;1.PingCode&#xff1b; 2. Worktile &#xff1b;3. 建米农业工程项目管理系统&#xff1b;4. 开创云数字农业管理平台&#xff1b; 5. Trimble Ag Software&#xff1b;6.Conservis&#xff1b; 7. Agworld &#xff1…...

linux 命令 tail

tail 是 Linux 中用于查看文件末尾内容的命令&#xff0c;常用于日志监控和大文件快速浏览。以下是其核心用法及常见选项&#xff1a; 基本语法 tail [选项] 文件名 常用选项 显示末尾行数 -n <行数> 或 --lines<行数> 指定显示文件的最后若干行&#xff08;…...

测试开发 - 正浩创新 - 一面面经(已OC)

自我介绍 实习过程中&#xff0c;有遇到过什么问题&#xff0c;是如何解决的 实习成果中的数据指标变化&#xff0c;人力消耗一直在递减&#xff0c;是什么原因 实习工作有很多模块&#xff0c;那一块工作对你的提升或者收获是比较大的 讲一下&#xff0c;简历中所罗列的几…...

实验8 搜索技术

实验8 搜索技术 一、实验目的 &#xff08;1&#xff09;掌握搜索技术的相关理论&#xff0c;能根据实际情况选取合适的搜索方法&#xff1b; &#xff08;2&#xff09;进一步熟悉盲目搜索技术&#xff0c;掌握其在搜索过程中的优缺点&#xff1b; &#xff08;3&#xff09;…...

VSTO(C#)Excel开发9:处理格式和字体

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…...

LinkedList底层结构和源码分析(JDK1.8)

参考视频&#xff1a;韩顺平Java集合 特点 LinkedList 底层实现了 双向链表 和 双端队列 的特点。可以添加任意元素&#xff08;元素可以重复&#xff09;&#xff0c;包括 null。线程不安全&#xff0c;没有实现同步。 LinkedList 底层结构 LinkedList 底层维护了一个双向链…...

数字内容体验的技术支柱是什么?

数据分析引擎构建基础 数字内容体验的技术底座始于对海量用户行为数据的深度解析。作为技术体系的根基&#xff0c;数据分析引擎通过实时采集、清洗与结构化处理&#xff0c;将分散的点击轨迹、停留时长及交互偏好转化为可操作的洞察。其核心能力体现在三方面&#xff1a;一是…...

C# 使用Markdown2Pdf把md文件转换为pdf文件

NuGet安装Markdown2Pdf库&#xff0c;可以把格式简单markdown文件转换为pdf。但该库用了Puppeteer Sharp&#xff0c;因此会在运行过程中提示指定Chrome浏览器路径或自动下载Chrome浏览器。 代码如下&#xff1a; using Markdown2Pdf;var converter new Markdown2PdfConverte…...

专家系统如何运用谓词逻辑进行更复杂的推理

前文&#xff0c;我们讲解了命题逻辑和谓词逻辑的基本概念、推理规则、应用以及一些简单的示例。具体内容可以先看我的文章&#xff1a;人工智能的数学基础之命题逻辑与谓词逻辑&#xff08;含示例&#xff09;-CSDN博客 那么形如专家系统这类复杂系统&#xff0c;是如何通过谓…...

html css网页制作成品——糖果屋网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

Ubuntu上部署Flask+MySQL项目

一、服务器安装python环境 1、安装gcc&#xff08;Ubuntu默认已安装&#xff09; 2、安装python源码 wget https://www.python.org/ftp/python/3.13.2/Python-3.13.2.tar.xz 3、安装Python依赖库 4、配置python豆瓣源 二、服务器安装虚拟环境 1、安装virtualenv pip3.10 ins…...

落雪音乐Pro 8.8.6 | 内置8条音源,无需手动导入,纯净无广告

洛雪音乐Pro版内置多组稳定音源接口&#xff0c;省去手动导入的繁琐操作&#xff0c;安装即可畅听海量音乐。延续原版无广告的纯净体验&#xff0c;支持歌单推荐与音源切换&#xff0c;满足个性化听歌需求。此版本仅支持在线播放&#xff0c;无法下载音乐&#xff0c;且与原版不…...

什么是全栈?

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点下班 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 &#x1f4c3;文章前言 &#x1f537;文章均为学习工…...

一些docker命令

一、基础命令 查看 Docker 版本 docker --version 或 docker version&#xff1a;显示 Docker 客户端和服务器的版本信息。 查看 Docker 系统信息 docker info&#xff1a;显示 Docker 系统的详细信息&#xff0c;包括镜像、容器数量、存储驱动类型等。 Docker 服务管理 s…...

《DeepSeek 开源 DeepGEMM:开启AI计算新时代的密钥》:此文为AI自动生成

《DeepSeek 开源 DeepGEMM&#xff1a;开启AI计算新时代的密钥》&#xff1a;此文为AI自动生成 引言&#xff1a;AI 计算的新曙光 在当今科技飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最为耀眼的领域之一。从语音助手到自动驾驶&#xff0c;从图像…...

OpenCV实现图像特征提取与匹配

‌一、特征检测与描述子提取‌ ‌选择特征检测器‌ 常用算法包括&#xff1a; ‌ORB‌&#xff1a;一种高效的替代SIFT和SURF的算法&#xff0c;主要用于移动机器人和增强现实等领域。适合实时应用&#xff0c;结合FAST关键点与BRIEF描述子‌。‌SIFT&#xff08;尺度不变特征变…...

将分支`XXX`合并到远程分支`master

将分支feat-task合并到远程分支master 首先&#xff0c;切换到本地的 master 分支 git checkout master确保你的本地 master 分支是最新的&#xff0c;拉取远程的更新 git pull origin master将 feat-task 分支的代码合并到 master 分支 git merge feat-task如果在合并过程…...

程序化广告行业(13/89):DSP的深入解析与运营要点

程序化广告行业&#xff08;13/89&#xff09;&#xff1a;DSP的深入解析与运营要点 大家好&#xff01;一直以来&#xff0c;我都对程序化广告行业保持着浓厚的学习兴趣&#xff0c;在探索的过程中积累了不少心得。今天就想把这些知识分享出来&#xff0c;和大家一起学习进步…...

XML文件格式的简介及如何用Python3处理XML格式对象

诸神缄默不语-个人技术博文与视频目录 文章目录 1. XML格式简介2. 格式化XML文件的工具3. Python处理XML&#xff1a;xml库1. xml.etree.\(c\)ElementTree2. xml.dom.minidom 4. 本文撰写过程中参考的其他网络资料 1. XML格式简介 可扩展标记语言 (Extensible Markup Language…...

通过qemu仿真树莓派系统调试IoT固件和程序

通过qemu仿真树莓派系统调试IoT固件和程序 本文将介绍如何使用 QEMU 模拟器在 x86 架构的主机上运行 Raspberry Pi OS&#xff08;树莓派操作系统&#xff09;。我们将从下载镜像、提取内核和设备树文件&#xff0c;到启动模拟环境&#xff0c;并进行一些常见的操作&#xff0…...

Oracle底层原理解析

Oracle 解析 1、union \ union all \ Intersect \ Minus内部处理机制&#xff08;优化&#xff09; 当查询语句中的where子句中使用到or时&#xff0c;可以用union all来代替。因为使用or查询语句的时候&#xff0c;引起全表扫描&#xff0c;并走索引查询 特别&#xff1a;当…...

深度解读DeepSeek部署使用安全(48页PPT)(文末有下载方式)

深度解读DeepSeek&#xff1a;部署、使用与安全 详细资料请看本解读文章的最后内容。 引言 DeepSeek作为一款先进的人工智能模型&#xff0c;其部署、使用与安全性是用户最为关注的三大核心问题。本文将从本地化部署、使用方法与技巧、以及安全性三个方面&#xff0c;对Deep…...

【前端三剑客】万字总结JavaScript

一、初识JavaScript 1.1 JavaScript 的作用 表单动态校验&#xff08;密码强度检测&#xff09; &#xff08; JS 产生最初的目的 &#xff09;网页特效服务端开发(Node.js)桌面程序(Electron)App(Cordova)控制硬件-物联网(Ruff)游戏开发(cocos2d-js) 1.2 HTML/CSS/JS 的关系…...