六十天Linux从0到项目搭建(第十天)(系统调用 vs 库函数/进程管理的建模/为什么进程管理中需要PCB?/exec 函数/fork原理与行为详解)

news2025/3/31 16:29:17

系统调用 vs 库函数:本质区别与协作关系


核心区别

特性系统调用(System Call)库函数(Library Function)
定义操作系统内核提供的 底层接口,直接操作硬件。封装系统调用的 高级函数,提供便捷功能。
权限需要切换到 内核态(高权限)。运行在 用户态(普通权限)。
性能开销大(需切换内核态)。开销小(纯用户态执行)。
稳定性影响系统全局(如文件读写)。仅影响当前进程。
例子open()read()fork()printf()fopen()malloc()

1. 系统调用(System Call)

特点

  • 直接与内核交互:是用户程序访问硬件/内核功能的唯一合法途径。

  • 通过软中断触发:如 x86 的 int 0x80 或 syscall 指令。

  • 权限提升:CPU 从用户态切换到内核态。

常见系统调用(Linux为例)

类别示例功能
文件操作open()read()打开/读取文件
进程控制fork()exec()创建进程/执行程序
内存管理brk()mmap()分配内存
网络通信socket()send()建立网络连接/发送数据

代码示例

#include <unistd.h>
int main() {
    // 直接调用系统调用 write(1=stdout, "Hello", 5)
    syscall(1, 1, "Hello", 5);  // Linux x86_64 的 write 系统调用号=1
    return 0;
}

2. 库函数(Library Function)

特点

  • 封装系统调用:提供更易用的接口(如 printf 封装 write)。

  • 纯用户态执行:不直接触发权限切换,效率更高。

  • 可能不依赖系统调用:如 strcpy() 纯内存操作,无需内核介入。

常见库函数(C标准库为例)

类别示例底层依赖的系统调用
文件操作fopen()fread()open()read()
内存管理malloc()free()brk()mmap()
字符串处理strcpy()strlen()(纯用户态)
格式化输出printf()write()

代码示例

#include <stdio.h>
int main() {
    printf("Hello");  // 库函数,内部调用 write() 系统调用
    return 0;
}

3. 协作关系

从 printf 看层级调用

用户程序调用 printf("Hello")  
  ↓  
C标准库处理格式化字符串(用户态)  
  ↓  
调用 write(1, "Hello", 5) 系统调用  
  ↓  
CPU 切换至内核态,执行内核的 write() 代码  
  ↓  
内核通过磁盘驱动写入硬件(如终端显示器)  

关键点

  1. 库函数是“包装纸”:隐藏系统调用的复杂性(如 printf 处理多种数据类型)。

  2. 系统调用是“终极手段”:只有需要硬件/内核资源时才触发。

  3. 部分库函数无需系统调用:如数学计算 sin()、字符串操作 memcpy()


为什么需要两层设计?

需求系统调用的限制库函数的优势
安全性频繁切换内核态导致性能下降。用户态执行,减少开销。
易用性原始接口复杂(如手动管理文件描述符)。提供高级抽象(如 FILE* 流)。
可移植性不同OS系统调用差异大。库函数屏蔽底层差异(如Windows/Linux的 fopen 实现不同,但接口一致)。

现实类比

  • 系统调用:像直接找银行行长办业务(严格但低效)。

  • 库函数:像通过柜台职员办业务(友好且高效,职员内部再找行长)。


总结

  1. 系统调用:内核提供的“终极接口”,权限高、开销大。

  2. 库函数:封装系统调用的“工具集”,更安全、易用。

  3. 协作模式:库函数处理复杂逻辑,必要时委托系统调用访问硬件。

记住

  • 当你调用 printf(),你是在用库函数;

  • 当 printf() 调用 write(),它是在用系统调用!

进程管理的建模:从程序到进程的转换


核心概念

1. 程序 vs 进程

程序(Program)进程(Process)
存储在磁盘上的静态二进制文件(如 /bin/ls)。程序被加载到内存后的 动态执行实例
文件 = 内容 + 属性(如权限、大小)。进程 = 代码 + 数据 + 内核数据结构

2. 操作系统的作用

  • 将程序转换为进程
    当你运行 ./a.out 时,OS 负责:

    1. 从磁盘读取可执行文件。

    2. 分配内存存放代码和数据。

    3. 创建管理进程的内核数据结构(如 task_struct)。


进程管理的建模过程

1. 磁盘中的程序(静态)

  • 本质:一个普通文件,包含:

    • 代码段(Text Segment):机器指令(如 main() 函数)。

    • 数据段(Data Segment):全局变量、静态变量。

    • 文件属性:权限、所有者、大小等(通过 ls -l 查看)。

2. 加载到内存(动态进程)

  • OS 的步骤

    1. 读取文件内容:将代码和数据加载到内存的特定区域。

    2. 创建进程控制块(PCB)

      • Linux 中为 task_struct,存储进程的所有属性。

      • 包括:进程ID(PID)、状态、优先级、内存映射、打开的文件等。

    3. 初始化执行上下文

      • 设置程序计数器(PC)指向 main() 的入口地址。

      • 分配栈空间(用于局部变量和函数调用)。

3. 进程的组成

// 进程 = 内核数据结构 + 代码/数据
struct task_struct {   // PCB(进程控制块)
    int pid;           // 进程ID
    char state;        // 运行状态(就绪、阻塞等)
    struct mm_struct *mm;  // 内存管理信息
    struct file *files;    // 打开的文件列表
    // ... 其他字段(优先级、父进程等)
};

// 代码和数据(用户空间)
.text: 机器指令(如 main())
.data: 全局变量
.heap: 动态分配的内存(malloc)
.stack: 函数调用栈

关键问题解答

1. 什么是“进程”?

  • 狭义task_struct(内核数据结构) + 代码/数据(内存中的内容)。

  • 广义:程序的一次动态执行过程,包括:

    • 执行状态(运行、就绪、阻塞)。

    • 资源占用(CPU、内存、打开的文件)。

2. 为什么需要PCB?

  • 统一管理:OS 通过 task_struct 跟踪所有进程,实现:

    • 调度:决定哪个进程获得CPU。

    • 隔离:防止进程A篡改进程B的内存。

    • 资源统计:记录CPU使用时间、内存占用等。

3. 从程序到进程的完整流程

磁盘上的 a.out 
  → OS 读取文件头(ELF格式) 
  → 分配内存空间(代码/数据/堆栈) 
  → 创建 task_struct 
  → 加入调度队列 
  → CPU 执行指令

现实类比

  • 程序:像一本食谱(静态文本)。

  • 进程:像厨师按照食谱做菜(动态过程),需要:

    • 工作台(内存):存放食材和工具。

    • 任务清单(PCB):记录做到哪一步、用了哪些资源。

  • OS:像餐厅经理,分配厨师(CPU)和厨房资源(内存)。


总结

  1. 程序是“尸体”,进程是“生命”

    • 程序是磁盘上的文件,进程是内存中的鲜活实例。

  2. PCB是进程的“身份证”

    • task_struct 让OS能管理进程的所有状态。

  3. OS是“幕后导演”

    • 默默完成程序→进程的转换,并调度资源。

为什么进程管理中需要PCB?——从Bash到子进程的完整链条


1. 为什么需要PCB?

PCB(进程控制块,如 task_struct)是操作系统的“进程管理中心”,核心作用如下:

功能具体实现类比
唯一标识进程通过 pid(进程ID)区分不同进程。像学生的学号,避免混淆。
保存进程状态记录运行/就绪/阻塞状态,供调度器决策。像任务清单上的“已完成/待处理”标记。
管理资源跟踪内存分配、打开的文件、网络连接等。像仓库的库存表。
实现进程隔离每个进程有独立的地址空间(通过 mm_struct 管理)。像银行客户的独立保险箱。
支持父子关系记录父进程 ppid,实现进程树(如 bash 是所有命令行进程的父进程)。像家族族谱。

没有PCB的后果

  • 进程无法被调度(OS不知道谁该运行)。

  • 内存泄漏(无法释放已终止进程的资源)。

  • 安全漏洞(进程可随意篡改他人内存)。


2. Bash与子进程的关系

(1) Bash本身是一个进程

  • Bash的PCB

    • 当你在终端输入命令时,Bash(/bin/bash)已作为进程运行,其PCB由OS维护。

    • 可通过 ps 查看:

      ps -ef | grep bash

      输出示例:

      ubuntu   1234  5678  0 10:00 pts/0    00:00:00 /bin/bash

(2) Bash如何创建子进程?

当你在Bash中运行 ./a.out 时:

  1. Bash调用 fork()

    • 复制当前Bash进程的PCB(生成一个子进程,继承Bash的环境变量、文件描述符等)。

    • 此时父子进程的代码执行位置完全相同(都停在 fork() 返回处)。

  2. 通过返回值分流

    • 子进程的 fork() 返回 0

    • 父进程(Bash)的 fork() 返回 子进程的PID

    • 代码示例:

      pid_t pid = fork();
      if (pid == 0) { 
          // 子进程执行流
          execvp("a.out", args);  // 加载a.out替换当前进程
      } else { 
          // 父进程(Bash)执行流
          wait(NULL);  // 等待子进程结束
      }
  3. 子进程运行目标程序

    • 子进程调用 exec() 系列函数,将自身替换为 a.out 的代码和数据。

    • 关键点

      • exec() 会替换代码段,但 保留原PCB(如 pid、打开的文件描述符)。


3. 子进程创建的核心机制

(1) fork() 的特性

特性说明
写时复制(COW)父子进程共享内存,直到一方尝试修改时才会复制(节省资源)。
执行顺序不确定由调度器决定父子进程谁先运行(可通过同步机制控制,如 wait())。
共享打开的文件子进程继承父进程的文件描述符(如终端输入/输出)。

(2) 代码分流的关键

fork();  // 执行后,从这里分裂出两个执行流

// 父子进程都会执行以下代码
if (pid == 0) {
    // 子进程专属代码
} else {
    // 父进程专属代码
}

现实类比

  • Bash:像餐厅经理(有自己的工作任务表-PCB)。

  • fork():经理复制一份自己的任务表,交给新员工(子进程)。

  • exec():新员工扔掉复制的任务表,换成具体的菜谱(a.out)。

  • wait():经理等待员工做完菜再继续自己的工作。


总结

  1. PCB是进程的“大脑”

    • 没有它,OS无法管理进程的生死、资源、状态。

  2. Bash是所有命令行进程的父进程

    • 通过 fork() + exec() 启动子进程,并通过PCB维护父子关系。

  3. fork() 的魔法

    • 复制PCB → 分流执行流 → 通过 exec() 加载新程序。

4 exec 函数家族详解:替换当前进程的“灵魂”

exec 是操作系统提供的一组系统调用,用于 将当前进程的代码和数据替换为一个新程序,但保留原有进程的PID、文件描述符等属性。可以理解为“进程的灵魂置换术”。


核心功能

  • 不创建新进程:仅在当前进程内加载新程序(与 fork() 不同)。

  • 完全替换:原程序的代码、数据、堆栈被新程序覆盖。

  • 继承环境:保留原进程的PID、打开的文件描述符、信号处理等。


exec 函数家族(6个变体)

均定义在 <unistd.h> 中,根据参数传递方式不同分为:

函数原型参数传递方式搜索路径适用场景
int execl(const char *path, const char *arg0, ..., NULL)列表传参(可变参数)需完整路径参数固定且较少时
int execle(const char *path, const char *arg0, ..., NULL, char *const envp[])列表传参 + 自定义环境变量需完整路径需指定环境变量
int execlp(const char *file, const char *arg0, ..., NULL)列表传参自动搜索 PATH调用系统命令(如 ls
int execv(const char *path, char *const argv[])数组传参需完整路径参数动态生成时
int execvp(const char *file, char *const argv[])数组传参自动搜索 PATH最常用(灵活+自动寻路)
int execvpe(const char *file, char *const argv[], char *const envp[])数组传参 + 自定义环境变量自动搜索 PATH需自定义环境变量且自动寻路

使用示例

1. 基本用法(execlp 调用 ls

#include <unistd.h>
#include <stdio.h>

int main() {
    printf("Before exec\n");
    // 执行 ls -l /, 自动搜索PATH
    execlp("ls", "ls", "-l", "/", NULL);  // 参数列表必须以NULL结尾
    printf("This line won't be reached!\n");  // exec成功时不会返回
    return 0;
}

输出

Before exec
total 16
drwxr-xr-x 2 root root 4096 Jan 1  1970 bin
...

2. 动态参数(execvp 调用自定义命令)

#include <unistd.h>

int main() {
    char *args[] = {"echo", "Hello, exec!", NULL};  // 参数数组
    execvp("echo", args);  // 自动搜索PATH中的echo
    return 0;
}

输出

Hello, exec!

3. 配合 fork() 创建子进程

#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {  // 子进程
        execlp("sleep", "sleep", "5", NULL);  // 子进程替换为sleep 5
    } else {  // 父进程
        wait(NULL);  // 等待子进程结束
        printf("Child finished sleeping.\n");
    }
    return 0;
}

关键注意事项

  1. 成功时无返回值exec 调用成功后,原进程的代码已被替换,后续代码不会执行。

  2. 失败时返回 -1:需检查错误(如文件不存在、无权限):

    c

    复制

    if (execvp("nonexistent", args) == -1) {
        perror("execvp failed");
    }
  3. 参数列表必须以 NULL 结尾:否则会导致未定义行为。

  4. 环境变量继承:默认继承父进程的环境变量,可用 execle 或 execvpe 自定义。


现实类比

  • fork():克隆一个完全相同的你(复制PCB)。

  • exec():把你的大脑换成爱因斯坦的(保留身体和身份证,但思想和能力全变)。


总结

  • 何时用:需要运行另一个程序,但不想创建新进程时(如Shell执行命令)。

  • 怎么选

    • 参数固定 → execlp

    • 参数动态 → execvp

    • 需自定义环境 → execvpe

  • 经典组合fork() + exec() + wait() 实现进程创建与程序加载。

5. fork() 的原理与行为详解

1. fork() 的核心功能

fork() 是Linux/Unix系统的一个系统调用,用于 创建一个与当前进程几乎完全相同的子进程。其核心行为包括:

  • 复制父进程的PCB(task_struct:子进程继承父进程的进程属性(如文件描述符、信号处理等)。

  • 复制内存空间:代码段、数据段、堆栈等(实际采用 写时拷贝 优化,见下文)。

  • 分配新的PID:子进程获得唯一的进程ID。

2. 代码与数据的处理
  • 代码段(只读)
    父子进程 共享同一份代码(因为代码不可修改,无需复制)。

  • 数据段(写时拷贝, Copy-On-Write, COW)

    • 初始时,父子进程 共享同一份物理内存(仅标记为“只读”)。

    • 当任一进程尝试 修改数据(如全局变量),操作系统会触发缺页异常,自动复制该内存页给修改方,实现隔离。

    • 优势:避免无意义的拷贝,提升性能。

3. 进程的独立性
  • 内存隔离:父子进程的修改互不影响(得益于COW)。

  • 调度独立:由操作系统决定父子进程的执行顺序。

4. 两个返回值的奥秘

fork() 的“一次调用,两次返回”是理解的关键:

pid_t pid = fork();  // 从这里分裂出两个执行流
  • 父进程fork() 返回 子进程的PID(>0)。

  • 子进程fork() 返回 0

  • 失败时:返回 -1(如进程数超限)。

底层原理

  • fork() 执行完成后,内核已将父进程的上下文(寄存器、PC等)复制到子进程。

  • 在 返回前的瞬间,父子进程的指令指针(PC)均指向 fork() 的下一条指令。

  • 返回值差异:内核通过检查进程的PCB(如 task_struct)决定返回哪个值。

5. 代码示例与分流
#include <unistd.h>
#include <stdio.h>

int main() {
    int x = 100;  // 父子进程初始共享x
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
    } else if (pid == 0) {  // 子进程
        x = 200;  // 触发写时拷贝,子进程的x独立
        printf("Child: x=%d\n", x);  // 输出 200
    } else {  // 父进程
        printf("Parent: x=%d\n", x); // 输出 100
    }
    return 0;
}
6. 关键结论
  • fork() 的本质:复制PCB + 虚拟内存映射(COW优化)。

  • 返回值设计:通过区分父子进程的PCB实现逻辑分流。

  • 独立性保障:写时拷贝确保进程间数据修改互不干扰。

类比

  • fork() 像细胞分裂,子细胞继承母细胞的“记忆”(PCB),但后续行为可独立发展。

  • 返回值像“出生证明”,子进程拿到“0”(新生儿标识),父进程拿到“出生登记号”(PID)。

pc均指向fork,pc是什么

PC(Program Counter)是什么?

PC程序计数器,Program Counter)是CPU中的一个 特殊寄存器,用于存储 当前正在执行的指令的内存地址。在x86架构中,它通常被称为 EIP(32位)或 RIP(64位),而在ARM架构中则直接称为 PC


PC 的核心作用

  1. 指向下一条要执行的指令

    • CPU 根据 PC 的值从内存中读取指令并执行。

    • 每执行完一条指令,PC 会自动递增(或跳转,如分支、函数调用)。

  2. 在 fork() 时的关键行为

    • 当调用 fork() 时,父子进程的 PC 都指向 fork() 的下一条指令

    • 这是 fork() 能“分裂”出两个执行流的根本原因。


fork() 与 PC 的关系

1. fork() 的执行流程

pid_t pid = fork();  // 执行到这里时,CPU的PC指向这一行
  • fork() 执行前

    • PC 指向 fork() 的调用指令(如 call fork)。

  • fork() 执行后

    • 父进程PC 指向 fork() 的下一条指令(即 if (pid == 0))。

    • 子进程PC 同样 指向 fork() 的下一条指令(因为子进程完全复制了父进程的上下文,包括 PC)。

2. 为什么 fork() 有两个返回值?

  • 内核的魔法

    • fork() 在 内核态 完成进程复制后,会 手动修改父子进程的返回值

      • 父进程的返回值:子进程的 pid

      • 子进程的返回值:0

  • PC 的作用

    • 父子进程的 PC 相同,因此都会从 fork() 的下一条指令继续执行。

    • 但返回值不同,导致代码分流(通过 if (pid == 0) 判断)。


示例代码分析

#include <unistd.h>
#include <stdio.h>

int main() {
    printf("Before fork\n");
    pid_t pid = fork();  // PC 指向这一行
    // fork() 返回后,PC 指向下一行(父子进程相同)
    
    if (pid == 0) {
        printf("Child: PID=%d\n", getpid());
    } else {
        printf("Parent: Child's PID=%d\n", pid);
    }
    return 0;
}

执行流程

  1. 父进程

    • fork() 返回子进程的 pid,进入 else 分支。

  2. 子进程

    • fork() 返回 0,进入 if 分支。

  3. 关键点

    • 父子进程的 PC 在 fork() 返回后指向同一位置,但返回值不同导致逻辑分流。


现实类比

  • PC 像书签:标记你当前读到书的哪一页。

  • fork() 像复印书

    • 复印后,你和复印本的书签都停在原书的同一页。

    • 但你可以选择继续读(父进程),或让复印本自己读(子进程)。


总结

  • PC 是指令指针:决定CPU下一步执行哪条指令。

  • fork() 复制 PC:父子进程从同一位置继续执行,但返回值不同。

  • 分流的关键:通过 if (pid == 0) 判断当前是父进程还是子进程。

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

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

相关文章

资本运营:基于Python实现的资本运作模拟

基于Python实现的一个简单的资本运营框架&#xff1b; ​企业生命周期演示&#xff1a;观察初创→成长→上市→并购全流程 ​行业对比分析&#xff1a;不同行业的财务特征和估值差异 ​资本运作策略&#xff1a;体验IPO定价、投资决策、并购整合等操作 ​市场动态观察&#xff…

当EFISH-SBC-RK3576遇上区块链:物联网安全与可信数据网络‌

在工业物联网场景中&#xff0c;设备身份伪造与数据篡改是核心安全隐患。‌EFISH-SBC-RK3576‌ 通过 ‌硬件安全模块 区块链链上验证‌&#xff0c;实现设备身份可信锚定与数据全生命周期加密&#xff0c;安全性能提升10倍以上。 1. 安全架构&#xff1a;从芯片到链的端到端防…

分布式系统面试总结:3、分布式锁(和本地锁的区别、特点、常见实现方案)

仅供自学回顾使用&#xff0c;请支持javaGuide原版书籍。 本篇文章涉及到的分布式锁&#xff0c;在本人其他文章中也有涉及。 《JUC&#xff1a;三、两阶段终止模式、死锁的jconsole检测、乐观锁&#xff08;版本号机制CAS实现&#xff09;悲观锁》&#xff1a;https://blog.…

【VSCode的安装与配置】

目录&#xff1a; 一&#xff1a;下载 VSCode二&#xff1a;安装 VSCode三&#xff1a;配置 VSCode 一&#xff1a;下载 VSCode 下载地址&#xff1a;https://code.visualstudio.com/download 下载完成之后&#xff0c;在对应的下载目录中可以看到安装程序。 二&#xff1a;安装…

脱围机制-react18废除forwardRef->react19直接使用ref的理解

采用ref&#xff0c;可以在父组件调用到子组件的功能 第一步&#xff1a;在父组件声明ref并传递ref interface SideOptsHandle {refreshData: () > Promise<void> }const sideOptsRef useRef<SideOptsHandle>(null) // 创建 ref<SideOpts ref{sideOptsRef…

Windows中安装git工具

下载好git安装包 点击next 选择安装目录 根据需要去勾选 点击next 点击next PATH环境选择第二个【Git...software】即可&#xff0c;再点击【Next】。 第一种配置是“仅从Git Bash使用Git”。这是最安全的选择&#xff0c;因为您的PATH根本不会被修改。您只能使用 Git Bash 的…

【CSS】CSS 使用全教程

CSS 使用全教程 介绍 CSS&#xff08;层叠样式表&#xff0c;Cascading Style Sheets&#xff09;是一种样式表语言&#xff0c;用于描述 HTML 或 XML 文档的布局和外观&#xff0c;它允许开发者将文档的内容结构与样式表现分离&#xff0c;通过定义一系列的样式规则来控制网页…

全分辨率免ROOT懒人精灵-自动化编程思维-设计思路-实战训练

全分辨率免ROOT懒人精灵-自动化编程思维-设计思路-实战训练 1.2025新版懒人精灵-实战红果搜索关键词刷视频&#xff1a;https://www.bilibili.com/video/BV1eK9kY7EWV 2.懒人精灵-全分辨率节点识别&#xff08;红果看广告领金币小实战&#xff09;&#xff1a;https://www.bili…

如何在IDEA中借助深度思考模型 QwQ 提高编码效率?

通义灵码上新模型选择功能&#xff0c;不仅引入了 DeepSeek 满血版 V3 和 R1 这两大 “新星”&#xff0c;Qwen2.5-Max 和 QWQ 也强势登场&#xff0c;正式加入通义灵码的 “豪华阵容”。开发者只需在通义灵码智能问答窗口的输入框中&#xff0c;单击模型选择的下拉菜单&#x…

LVS的 NAT 模式实验

文章目录 目录 文章目录 概要 IP规划与题目分析 实验步骤 一、nginx配置&#xff08;rs1、rs2、rs3&#xff09; 二、LVS配置 三、客户端配置 四、防火墙和selinux配置 实验结果 痛点解答 概要 LVS/NAT lvs/nat网络地址转换模式&#xff0c;进站/出站的数据流量经过分发器(IP负…

【MacOS】2025年硬核方法清理MacOS中的可清除空间(Purgeable space)

背景 MacOS使用一段时间之后&#xff0c;硬盘空间会越来越少&#xff0c;但自己的文件没有存储那么多&#xff0c;在储存空间中可以发现可用空间明明还剩很多&#xff0c;但磁盘工具却显示已满&#xff0c;见下图。 尝试解决 df -h 命令却发现磁盘已经被快被占满。使用du命…

ue材质学习感想总结笔记

2025 - 3 - 27 1.1 加法 对TexCoord上的每一个像素加上一个值&#xff0c;如果加上0.1&#xff0c;0.1&#xff0c; 那么左上角原来0,0的位置变成了0.1,0.1 右上角就变成了1.1,1.1&#xff0c;那么原来0,0的位置就去到了左上角左上边&#xff0c;所以图像往左上偏移。 总而言…

信而泰PFC/ECN流量测试方案:打造智能无损网络的关键利器

导语&#xff1a; AI算力爆发的背后&#xff0c;如何保障网络“零丢包”&#xff1f; 在当今数据中心网络中&#xff0c;随着AI、高性能计算&#xff08;HPC&#xff09;和分布式存储等应用的飞速发展&#xff0c;网络的无损传输能力变得至关重要。PFC&#xff08;基于优先级的…

CNN和LSTM的计算复杂度分析

前言&#xff1a;今天做边缘计算的时候&#xff0c;在评估模型性能的时候发现NPU计算的大部分时间都花在了LSTM上&#xff0c;使用的是Bi-LSTM&#xff08;耗时占比98%&#xff09;&#xff0c;CNN耗时很短&#xff0c;不禁会思考为什么LSTM会花费这么久时间。 首先声明一下实…

UniApp 表单校验两种方式对比:命令式与声明式

目录 前言1. 实战2. Demo 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 以下主要针对Demo讲解&#xff0c;从实战中的体会 何为命令式 何为声明式 命令式的体验&#xff0c;随时都会有提交的按钮&#xff…

LCR 187. 破冰游戏(python3解法)

难度&#xff1a;简单 社团共有 num 位成员参与破冰游戏&#xff0c;编号为 0 ~ num-1。成员们按照编号顺序围绕圆桌而坐。社长抽取一个数字 target&#xff0c;从 0 号成员起开始计数&#xff0c;排在第 target 位的成员离开圆桌&#xff0c;且成员离开后从下一个成员开始计数…

centOS 7.9 65bit 修复Openssh漏洞

一、背景&#xff1a; 在使用centos 7.9 64bit版本操作系统时有扫描出如下的漏洞&#xff1a; 二、修复openssh漏洞操作 升级注意事项 (一下所有的操作默认都是root或者管理员权限&#xff0c;如果遇到权限问题每个指令以及指令组合都要在前面加sudo) 1、查看CentOS操作系统信…

JDBC-添加数据

文章目录 准备数据库添加数据引入数据库依赖包 准备数据库 自行安装软件&#xff0c;利用小皮内嵌的数据 添加数据 引入数据库依赖包 结构 drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://127.0.0.1:3308/yanyuuserroot passwordrootpackage com.yanyu;import java.sql.*;…

衡石科技HENGSHI SENSE异构数据关联技术深度解析:揭秘5-8倍性能提升背后的“异构过滤“架构

引言&#xff1a;多源数据关联的行业痛点 在大数据时代&#xff0c;企业数据通常分散在多个异构系统中——关系型数据库、NoSQL、数据仓库、湖仓一体平台等。根据Forrester调研&#xff0c;超过78%的企业需要同时访问5种以上不同类型的数据源进行分析&#xff0c;但传统ETL和跨…

基于Netlify + Localtunnel 实现本地项目“无服务器”部署上线

基于Netlify Localtunnel 实现本地项目“无服务器”部署上线 1. 先看效果图2. 实现步骤2.1 分两步走2.2 netlify 部署前端资源2.3 Localtunnel 映射 localhost 服务 3. 其它工具内网穿透工具对比4. 总结5. 参考资料 1. 先看效果图 地址&#xff1a;zqchat 2. 实现步骤 2.1 …