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

Linux:进程入门(进程与程序的区别,进程的标识符,fork函数创建多进程)

往期文章:《Linux:深入了解冯诺依曼结构与操作系统》

Linux:深入理解冯诺依曼结构与操作系统-CSDN博客

目录

1. 概念

2. 描述进程

3. 深入理解进程的本质

4. 进程PID

4.1 指令获取PID

4.2 geipid函数获取PID

4.3 kill指令终止进程

4.4 进程信息文件夹

(1)exe

(2)cwd

5. 进程PPID

5.1 getppid函数获取PPID

5.2 fork函数创建子进程

6. 创建多进程

7. fork函数如何返回两个值


1. 概念

进程(Process)是指一个正在执行的程序实例。在操作系统中,进程是资源分配和调度的基本单位。可执行程序与进程的区别:可执行程序是一组指令的集合,它存储在磁盘上,而进程则是程序在执行时的一个实例,它存在于内存中

2. 描述进程

操作系统也称之为Operating System,缩写就是OS。

操作系统笼统的分为内核(kernel)和外壳程序。内核有进程管理、内存管理、文件管理和驱动管理。操作系统管理任何对象,都是对其属性进行管理,遵守先描述,再组织的原则。

因此,操作系统管理进程,相当于管理它的属性,会把进程属性放在一个叫做进程信息控制块的数据结构当中,就是进程属性的集合。这也称为PCB(process control block),Linux操作系统下的PCB是task_struct

下面是task_struct结构体中包含的内容:

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息

3. 深入理解进程的本质

如下图,进程的前身就是一个可执行程序,它主要包含代码和数据,且在硬盘当中。可执行程序在windows系统中一般以.exe结尾,在Linux系统中一般没有特定的后缀结尾,且通常不跟后缀。

当一个可执行程序启动运行时,其代码与数据将被载入内存之中。在这一过程之前,操作系统内核会创建一个名为task_struct的结构体对象,该对象详细记录了进程的各种属性。这些属性包括但不限于进程标识符(pid)、状态信息、优先级等。特别地,memptr指针负责记录内存中myexe程序的起始地址,确保进程能够正确地访问和执行程序代码。

进程 = 内核数据结构(task_struct) + 程序的代码和数据

当多个可执行程序同时运行时,task_struct结构体内部采用特定的数据结构,将所有进程串联起来。设想task_struct中包含一个指向下一个结构体的指针,那么将存在一个结构体指针list,它指向链表中的第一个task_struct对象。随着新进程的创建,它们的task_struct对象会被前一个对象的next指针串联起来,从而在操作系统中形成了一个调度队列

CPU的寄存器并不直接存储程序的代码和数据,而是通过list指针定位到相应的task_struct对象,并将其信息载入寄存器。因此,当CPU调度内存中的myexe进程时,实际上是在操作该进程的task_struct对象,进而间接执行程序代码。

我们可以用一个类比来理解这个过程:假设张三正在求职,他提交了一份简历给公司的人力资源部门(HR)。这份简历包含了张三的个人详细信息、实习经历和项目经验,这些信息集合就如同进程的task_struct结构体,记录了张三的“属性”。当HR收到众多简历并逐一审核时,求职者本人对于这一过程是一无所知的。这与CPU调度进程的情形相似,CPU并不直接运行内存中的程序,而是通过操作task_struct结构体对象来间接实现对进程的调度。

4. 进程PID

4.1 指令获取PID

不管是在windows系统中,你双击某个应用,还是在Linux系统中,你执行某些指令或者运行某个可执行程序,当这些程序跑起来都叫做进程。不过进程一般分为两种,第一种是执行完就退出的进程,像Linux系统下的ls pwd等指令;第二种是执行完一直不退出,直到用户关闭,像window系统中的QQ,微信等应用,这种进程叫做常驻型进程。

下面写一份C语言代码,在main函数使用while循环搞个死循环,内部是每隔一秒钟打印一句话。sleep函数的作用是使当前进程暂停执行指定的秒数,该函数的原型通常在<unistd.h>头文件中定义

当程序运行起来,会不断打印“hello linux!”。

 这时我们再打开一个Xshell程序,就可以在不打扰上面进程的情况下输入新指令并运行。

 我们可以使用ps指令来查看进程信息。其中head -1表示拿到进程信息的第一行,grep加某些进程名,表示拿到该进程名那行信息。你会发现COMMAND这列中含有grep指令,这是因为gerp myproc本身就含有myproc,也会打印出来。想要去掉它,grep后加上-v grep,就是忽略grep相关的文本信息。

  • -a:显示所有终端下的进程。
  • -x:显示没有控制终端的进程(在后台运行)。
  • -j:显示与作业控制相关的信息。

我们观察上图,第一行中有许多属性名词,其中PID表示进程的唯一标识符,PPID表示父进程的标识符。myproc进程pid是4340。如果我们按下Ctrl+C按键,会中断该进程。

 当再次启动进程时,使用ps指令获取进程信息,pid值为6336。你会发现同样都是myproc的进程,pid值发生改变。因为系统使用一个累加的计数器维护进程的PID值,在你启动进程时,操作系统也不断在请求任务。所以,PID值出现变化且不连续是很正常的。

4.2 geipid函数获取PID

getpid是一个系统调用级函数,可以获取进程的id值。需要包含两个头文件,分别是unistd.h和sys/types.h。其中pid_t其实本质就是long int类型,只不过被typedef封装了一下。

使用getpid函数不用频繁获取,只需获取一次,因为一个进程启动之后,id值不会改变的,除非重新启动一次。当myproc程序执行起来后,可以看到进程id值是8042。我们使用ps指令获取myproc进程的信息,会发现pid值也是8042。

4.3 kill指令终止进程

如果你想要终止一个进程,可以在键盘上按下Ctrl + C的按键,发出终止信号。或者使用kill指令,使用kill -l可以查看kill指令的选项,其中9对应的选项就是终止进程。

终止进程操作如上图所示,输入kill + -9 + 进程id值,在另外一恶搞Xshell程序中可以看到myproc进程停止,显示了Killed信息。

4.4 进程信息文件夹

(1)exe

我们刚刚通过ps指令可以获取进程的一部分信息。在Linux操作系统下,一切皆文件。我们使用ls指令查看根目录,会发现有个proc目录。

proc就是process(进程)的缩写,再使用ls指令查看该目录,可以发现许多以数字命名的目录,这些就是某个进程的id值,里面存放的就是该进程的相关信息。

运行myproc程序后,生成一个pid值为19775的进程,使用ls命令查看/proc路径下的文件,其中就有名为19775文件夹。该文件夹存放的就是该进程的详细信息。

我们查看/proc/19775路径下的文件,会发现里面有许多内容。今天需要认识一下exe和cwd。进程是被某个可执行程序启动,exe存放的就是该可执行程序的路径

当我们再打开一个Xshell程序,进入到myproc的目录下,删除该可执行程序,你会发现进程还是在运行。因为进程已经被加载到内存当中,删除硬盘的可执行程序不会造成影响。但是再次查看/proc/19775路径下的文件,会发现exe显示该路径下的可执行程序已被删除。

(2)cwd

cwd全称是current working directory,意思是当前工作目录。我们在C语言中创建一个文件,如果没有指定绝对路径,默认生成在当前路径下。下面我们写个代码验证一下。

运行myproc程序,过几秒终止进程。查看当前目录,会发现多了一个file.txt文件。所以使用fopen新建一个文件时,不是你以为的相对路径,而是拿到cwd再加上你输入的文件名,形成一个绝对路径。还有什么方式可以证明上面的说法呢?

我们可以使用一个系统调用函数chdir,它的作用就是改变当前进程的工作目录。我们在myproc.c中使用chdir函数,修改当前工作目录为home目录下的普通用户,也就是我正在使用的用户。如果修改到根目录或者家目录,无法新建文件夹,因为普通用户没有写权限,只有超级用户才可以新建文件或者目录。

当我们启动myproc程序后,立即查看/proc/24404中内容,会发现cwd变成了普通用户的目录。再使用ls命令查看工作目录,发现有file.txt文件。这就验证了在代码中新建文件,如果不写绝对路径,会在输入的文件名前加上当前工作目录。

5. 进程PPID

5.1 getppid函数获取PPID

ppid是指parent process id,即某个进程的父进程id值。

其中getppid函数,是获取某个进程的父进程id值。

 修改一下myproc.c中的代码,获取一下父进程id,并打印出来。

 当我们启动myproc程序,运行一会后,终止该程序,再启动该程序,重复三次。你会发现它们的父进程id值都是19496。

我们使用ps指令查看该父进程信息,发现该进程的command(执行的指令)是-bash。其中bash是Linux系统下的命令行解释器,类似于windows系统中的cmd。

因此有个结论,在Linux操作系统启动之后,命令行上执行指令或者执行程序,本质上都是bash的进程创建的子进程,由这些子进程执行我们的代码

5.2 fork函数创建子进程

fork函数也是系统调用函数。函数原型如上,返回值类型是pid_t,不用传参。它的作用是在当前进程下创建一个子进程。

修改myproc.c中的代码,一开始打印一下当前进程的pid和ppid。之后调用fork函数,试着打印子进程的pid和ppid。

运行myproc程序,你会发现打印了三行语句。其中第一行语句是第一个printf函数打印的,pid值为29447的进程应该是myproc启动后的进程它的父进程就是上面提到的bash。

但是下面打印了两行语句,第二行语句的pid值为29447,ppid值是26892,应该是当前程序的进程。最后一行语句中,pid值是29448,ppid值是29447,它的父进程就是myproc程序启动后的进程,说明这是fork函数创建出来的子进程,并且pid值是连续的。

可以得出结论,调用fork函数,当前进程会创建一个子进程,这两个进程会同时执行后面的代码,相当于两个执行流分支。因为这两个进程是连续创建的,它们的pid值连续。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());pid_t id = fork();if (id > 0){while (1){printf("我是父进程,pid: %d, ppid: %d, ret id: %d\n", getpid(), getppid(), id);sleep(1);}}else if (id == 0){while (1){printf("我是子进程,pid: %d, ppid: %d, ret id: %d\n", getpid(), getppid(), id);sleep(1);}}}

 fork函数调用成功,给父进程返回子进程的pid,给子进程返回0。如果调用失败,会设置错误值到errno变量中。

运行结果如上,fork创建进程后,当前进程接收到子进程的id值,子进程接收到0。那么为什么if else语句看起来能同时成立,且有两个返回值?

上面有提到,进程 = 内核数据结构(task_struct) + 程序的代码和数据。那么fork函数创建一个子进程时,操作系统会创建一个task_struct结构体对象。程序中的代码因为是只读的,子进程与父进程共享代码。

而子进程会私有一份数据,因为两个进程间数据互相修改,可能会触发某些条件导致程序崩溃,所以进程之间具有很强的独立性,一个进程崩溃不会影响另外一个进程。这就类似于手机上启动许多应用,如微信,抖音等,如果微信崩溃,不会影响抖音的运行。

因为fork函数创建子进程后,会出现两个执行流,那么此时fork函数返回一个值时,有两个执行流进行返回,并且进程间的数据是各自私有的,那么id变量会有两份。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int g_val = 0;int main()
{printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());pid_t id = fork();if(id > 0){while(1){printf("我是父进程,pid: %d, ppid: %d, ret id: %d, g_val: %d\n", getpid(),     getppid(), id, g_val);sleep(1);}}else if(id == 0){while(1){printf("我是子进程,pid: %d, ppid: %d, ret id: %d, g_val: %d\n", getpid(), getppid(), id, g_val);g_val++;sleep(1);}}}

 如上我们可以定义一个全局变量g_val,在父进程中只打印出来,在子进程中不仅打印出来,每次让g_val变量加1。

结果如上,父进程的g_val值一直是0,子进程的g_val值不断变化。这就证明了子进程会私有一份数据。

6. 创建多进程

#include <iostream>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
using namespace std;const int num = 10;void SubProcessRun()
{while(true){cout << "I am a sub process, pid: "<< getpid() << " ,ppid: "<<getppid()<<endl;sleep(5);}
}int main()
{   vector<pid_t> childproc;for(int i = 0; i < num; i++){pid_t id = fork();if (id == 0){//子进程SubProcessRun();}//走到这里,只能是父进程执行childproc.push_back(id);}//父进程遍历所有子进程的pidcout << "我的所有子进程:";for(auto child: childproc){cout<<child << " ";}cout << endl;sleep(10);while(true){cout << "我是父进程,pid: "<< getpid()<<endl;sleep(1);}return 0;
}

使用一个for循环,使用fork创建子进程。每个子进程再调用SubProcessRun函数,死循环不断打印pid值。 使用vector数组存储子进程的pid值,然后遍历打印出来。父进程也执行个死循环,不退出。

运行该程序,就可以一次性创建多个连续进程。

7. fork函数如何返回两个值

fork函数为什么会返回两个返回值?

因为fork函数内部再返回值之前,会先创建子进程,创建进程会先在内核中创建task_struct结构体对象,用于管理进程的属性,然后代码共享,数据拷贝父进程的。这时,子进程已经开始运行,那么就会有两个执行流,最后返回值也是代码,就会被父子进程各自返回一次。

不过还有一个问题没有弄清楚,return语句返回的是一个值。为什么两个执行流返回时,这个值就变成两个不同的值?这是后面会解决的问题。


创作充满挑战,但若我的文章能为你带来一丝启发或帮助,那便是我最大的荣幸。如果你喜欢这篇文章,请不吝点赞、评论和分享,你的支持是我继续创作的最大动力!

相关文章:

Linux:进程入门(进程与程序的区别,进程的标识符,fork函数创建多进程)

往期文章&#xff1a;《Linux&#xff1a;深入了解冯诺依曼结构与操作系统》 Linux&#xff1a;深入理解冯诺依曼结构与操作系统-CSDN博客 目录 1. 概念 2. 描述进程 3. 深入理解进程的本质 4. 进程PID 4.1 指令获取PID 4.2 geipid函数获取PID 4.3 kill指令终止进程 …...

索尼MDR-M1:超宽频的音频盛宴,打造沉浸式音乐体验

在音乐的世界里&#xff0c;每一次技术的突破都意味着全新的听觉体验。 索尼&#xff0c;作为音频技术的先锋&#xff0c;再次以其最新力作——MDR-M1封闭式监听耳机&#xff0c;引领了音乐界的新潮流。 这款耳机以其超宽频播放和卓越的隔音性能&#xff0c;为音乐爱好者和专…...

【Linux】线程的概念

一、线程的概念 1.1 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff0c;更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&#xff0c;本质是在进程地址空间内运行在Linux系统中&#xff0c;在CPU眼中…...

centos7.9环境下mysql8数据库双机互备环境部署

为了实现mysql数据库的高可用性,数据库采用双机互备方式部署。双机互备能够避免单点故障造成的系统故障,由于两个节点都可以进行读写,同时也可以提高整个系统的数据读写并发性能。 1. 数据库安装 centos7安装mysql8 community 服务器IP:192.168.76.84 服务器IP:192.16…...

git 报错git: ‘remote-https‘ is not a git command. See ‘git --help‘.

报错内容 原因与解决方案 第一种情况&#xff1a;git路径错误 第一种很好解决&#xff0c;在环境变量中配置正确的git路径即可&#xff1b; 第二种情况 git缺少依赖 这个情况&#xff0c;网上提供了多种解决方案。但如果比较懒&#xff0c;可以直接把仓库地址的https改成ht…...

mysql学习教程,从入门到精通,SQL GROUP BY 子句(31)

1、SQL GROUP BY 子句 当然&#xff01;在SQL中&#xff0c;GROUP BY 子句用于将结果集中的多个记录组合成一个摘要记录。通常&#xff0c;它用于结合聚合函数&#xff08;如 COUNT(), SUM(), AVG(), MAX(), MIN() 等&#xff09;来计算每个组的汇总信息。以下是一个详细的例子…...

pip 和 conda 的安装区别

在决定使用 pip 和 conda 安装包时&#xff0c;了解这两个包管理器之间的主要区别非常重要。以下是细分&#xff1a; 1. 区别 1.1. Package Management System 包裹管理系统 Pip: &#xff1a; Primarily used for Python packages. 主要用于 Python 包。 Installs package…...

大学生就业招聘:Spring Boot系统的架构分析

大学生就业招聘系统的设计与实现 摘要 随着信息互联网信息的飞速发展&#xff0c;大学生就业成为一个难题&#xff0c;好多公司都舍不得培养人才&#xff0c;只想要一专多能之人才&#xff0c;不愿是承担社会的责任&#xff0c;针对这个问题开发一个专门适应大学生就业招聘的网…...

线段树模板

文章目录 线段树练习题目线段树概念区间维护辅助函数创建线段树 &#xff1a;build修改线段树 &#xff1a;modify查询线段树&#xff1a;query 全部代码 线段树 练习题目 洛谷题单 【模板】线段树 1 【模板】线段树 2 开关 扶苏的问题 线段树概念 线段树是一种高级数据结构&a…...

【TypeScript】知识点梳理(三)

#void前面提到了代表空&#xff0c;但有个特殊情况&#xff0c;是空不是空&#xff0c;细谈是取舍&#xff0c;但我们不深究hhh# 代码示例&#xff1a; type func () > voidconst f1: func function() {return true; } 定义了空&#xff0c;返回非空值&#xff0c;理论…...

题解:SP1741 TETRIS3D - Tetris 3D

这是一道二维线段树&#xff08;树套树&#xff09;标记永久化的模版题 前置知识点&#xff08;来自董晓算法&#xff09; 好&#xff0c;现在开始我们的分析&#xff1a; 题意简述&#xff1a; 在一个二维平面内&#xff0c;有给定的坐标&#xff0c;在这个坐标范围内加上…...

EWSTM8 IAR for STM8 软件分享

1. 软件简介 EWSTM8&#xff0c;即 IAR for STM8&#xff0c;全称为 IAR Embedded Workbench for STM8&#xff0c;它是 IAR ARM 嵌入式工作台之一&#xff0c;用于开发 STM8。IAR 有多个不同名的版本&#xff0c;对应不同的开发对象。 EWSTM8最新版本为V3.11&#xff08;202…...

非机动车检测数据集 4类 5500张 电动三轮自行车 voc yolo

非机动车检测数据集 4类 5500张 电动三轮自行车 voc yolo 非机动车检测数据集介绍 数据集名称 非机动车检测数据集 (Non-Motorized Vehicle Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7等&#x…...

Chromium 中JavaScript FileReader API接口c++代码实现

FileReader 备注&#xff1a; 此特性在 Web Worker 中可用。 FileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#xff0c;使用 File 或 Blob 对象指定要读取的文件或数据。 文件对象可以从用户使用 <…...

k8s 中微服务之 MetailLB 搭配 ingress-nginx 实现七层负载

目录 1 MetailLB 搭建 1.1 MetalLB 的作用和原理 1.2 MetalLB功能 1.3 部署 MetalLB 1.3.1 创建deployment控制器和创建一个服务 1.3.2 下载MealLB清单文件 1.3.3 使用 docker 对镜像进行拉取 1.3.4 将镜像上传至私人仓库 1.3.5 将官方仓库地址修改为本地私人地址 1.3.6 运行清…...

南昌网站建设让你的企业网站更具竞争力

南昌网站建设让你的企业网站更具竞争力 在当今竞争激烈的市场环境中&#xff0c;一个高质量的网站不仅是企业形象的展示平台&#xff0c;更是吸引客户、提升业绩的重要工具。南昌作为江西的省会城市&#xff0c;互联网产业的蓬勃发展为企业网站建设提供了良好的机遇。 首先&am…...

【重学 MySQL】五十三、MySQL数据类型概述和字符集设置

【重学 MySQL】五十三、MySQL数据类型概述和字符集设置 MySQL数据类型概述MySQL字符集设置注意事项 MySQL数据类型概述 MySQL是一个流行的关系型数据库管理系统&#xff0c;它支持多种数据类型&#xff0c;以满足不同数据处理和存储的需求。理解并正确使用这些数据类型对于提高…...

《计算机原理与系统结构》学习系列——计算机的算数运算(上)

系列文章目录 目录 ALU行波进位加法器超前进位加法器整数运算加减法乘法无符号数相乘N位乘法数的工作流程N位乘法器改进&#xff1a;硬件资源更快速的乘法 MIPS中的乘法除法 32位除法器流程除法器改进 更快速的除法 MIPS中的除法总结 ALU ALU功能&#xff1a;对a&#xff0c;…...

如何在华为云服务器查看IP地址,及修改服务器登录密码!!!

1.在华为云服务器查看IP地址 (1).第一步&#xff1a; 先找到控制台 (2).第二步&#xff1a; 点击华为云Flexus云服务 (3)第三步&#xff1a; 找到公网IP&#xff0c;就找到华为云服务器IP地址啦。 注意&#xff1a;在操作以上步骤的前提是要已注册华为云账号及购买云服务器…...

JAVA并发编程高级——JDK 新增的原子操作类 LongAdder

LongAdder 简单介绍 前面讲过,AtomicLong通过CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器来说它的性能已经很好了,但是JDK开发组并不满足于此。使用AtomicLong 时,在高并发下大量线程会同时去竞争更新同一个原子变量,但是由于同时只有一个线程的CAS操作会成功,…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...