Linux 入门:操作系统进程详解
目录
一.冯诺依曼体系结构
一). 软件运行前为什么要先加载?程序运行之前在哪里?
二).理解数据流动
二.操作系统OS(Operator System)
一).概念
二).设计OS的目的
三).如何理解操作系统OS的“管理”
四).系统调用和库函数概念
三.进程
一).进程基本概念与基本操作
1.描述进程-PCB
2.task_ struct
3.查看进程
1). 进程的信息可以通过 /proc 系统文件夹查看
2). 大多数进程信息同样可以使用top和ps这些用户级工具来获取
4.通过系统调用获取进程标示符
5.通过系统调用创建进程-fork初识
1).认识fork
2).父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
3).fork有两个返回值
4).fork 之后通常要用 if 进行分流
二).进程状态
1.Linux内核源代码怎么说
2.运行 && 阻塞 && 挂起
3.进程状态查看
4.Z(zombie)-僵尸进程
5.孤儿进程
三).进程优先级
1.基本概念
2.查看系统进程
3.查看修改进程优先级
4.补充概念---竞争、独立、并行、并发
四).进程切换
1.死循环进程如何运行
2. CPU和寄存器
3.如何切换
五).Linux真实的调度算法
1.优先级
2.活动队列
3.过期队列
4.active指针和expired指针
一.冯诺依曼体系结构
这里我们讨论学习的是红色的数据信号。
我们所认识的计算机,都是由一个个的硬件组件组成
- 输入单元:包括键盘, 鼠标,扫描仪, 写板,磁盘等
- 中央处理器(CPU):含有运算器和控制器等
- 输出单元:显示器,打印机,磁盘等
- 存储器:内存
关于冯诺依曼,必须强调几点:
1.这里的存储器指的是内存。
2.不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)。
3.外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。
4.一句话,所有设备都只能直接和内存打交道。
那为什么有这些设定呢?速度差距大。
我们设计出不同存储速度的内存进行存储。当代计算机是性价比的产物。
我们从两个问题开始详细认识这个体系。
一). 软件运行前为什么要先加载?程序运行之前在哪里?
二).理解数据流动
请解释,从你登录上qq开始和某位朋友聊天开始,数据的流动过程。从你打开窗口,开始给他发消息,到他的到消息之后的数据流动过程。如果是在qq上发送文件呢?
二.操作系统OS(Operator System)
一).概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS),操作系统是一款进行软硬件管理的软件。笼统的理解,操作系统包括:
• 内核(进程管理,内存管理,文件管理,驱动管理)
• 其他程序(例如函数库,shell程序等等)
二).设计OS的目的
对下,与硬件交互,管理所有的软硬件资源(目的)
对上,为用户程序(应用程序)提供一个良好的执行环境(手段)
对于操作系统我们要认识以下几点:
1.软硬件体系结构------>层状结构
2.访问操作系统,必须使用系统调用------其实就是函数,不过是系统提供的
3.我们的程序,只要你判断出它访问了硬件,那么它必须贯穿整个软硬件体系结构。比如:printf的本质:是你把你的数据写到了硬件里。
4.库可能在底层封装了系统调用
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
三).如何理解操作系统OS的“管理”
对于OS的管理,我们使用生活中的例子来进行描述。对于一件事情我们分为两个步骤1.决策2.执行
管理的例子 ----- 学生,辅导员,校长。
加速理解:
1.对于校长管理学生,我们可以知道,我们一学期甚至大学四年都见不到校长几次 ,而对于校长的决策,比如:什么时候举办运动会,将全校最高的几个男生组成篮球队打比赛,我们都是要去执行的。
2.对于选全校身高最高的学生这个决策如何进行呢?校长一个一个的找同学去问吗?并不是,而是通过学生的身高数据去筛选。
3.那么,身高数据从哪来?那当然是辅导员统计上交的啦。
那么,我们可以得到几个结论:
1.要管理,管理者和被管理者,可以不需要见面
2.管理者怎么管理被管理者,根据“数据”进行管理
3.不需要见面,如何得到数据?由中间层获取。
那么校长对于学生数据就可以进行数据建模,使用结构体来描述一个学生的信息
校长进行数据建模的行为,我们可以认为是先描述,再组织。
操作系统对于计算机管理硬件
1. 描述起来,用struct结构体。
2. 组织起来,用链表或其他高效的数据结构。
四).系统调用和库函数概念
在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
三.进程
操作系统是怎么管理进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!
一).进程基本概念与基本操作
课本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体
加速理解:
我们可以简单的形容为我们找工作的过程:内存中的代码和数据就是“我们”,进程控制块就是“我们的简历”,CPU就是“面试官”,进程列表就是“我们的简历在排队”,我们在等待面试官筛选的过程本质上是我们的简历在等待被筛选,也就是进程控制块在被读取而不是我们的代码和数据,而进程控制块上的代码和数据地址就是“我们的电话号码和居住地址”。这样应该就能稍微理解进程了。
1.描述进程-PCB
task_struct ---- PCB的一种
在Linux中描述进程的结构体叫做task_struct。
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息
总结:
进程 = 内核数据结构对象 + 自己的代码和数据
在这里就是:进程 = PCB(task_struct) + 自己的代码和数据
2.task_ struct
内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
- 上下文数据: 进程执行时处理器的寄存器中的数据。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息。
组织进程
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里
3.查看进程
1). 进程的信息可以通过 /proc 系统文件夹查看
如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹。
2). 大多数进程信息同样可以使用top和ps这些用户级工具来获取
我们历史上执行的所有的指令,工具,自己的程序,运行起来,全部都是进程。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{while(1){sleep(1);printf("我是一个进程pid: %d\n",getpid());}return 0;
}
getpid() 的作用
查看运行程序的进程 ps axj | grep code
添加属性列:ps axj | head -1;ps axj | grep code
杀掉进程 ctrl + c 或 kill -9 pid
4.通过系统调用获取进程标示符
- 进程id(PID)
- 父进程id(PPID)
1 #include <stdio.h>2 #include <unistd.h>3 #include <sys/types.h>4 5 int main()6 {7 while(1)8 {9 sleep(1);10 printf("我是一个子进程pid: %d,我的父进程:%d\n",getpid(),getppid());11 } 12 }
那么这个135370进程是什么呢?
操作系统会给每一个用户分配一个bash
查看bash:while :; do ps axj |head -1;ps axj | grep 'bash' | grep -v grep ; sleep 1 ; done
5.通过系统调用创建进程-fork初识
1).认识fork
运行 man fork
1 #include <stdio.h>2 #include <unistd.h>3 #include <sys/types.h>4 5 int main()6 {7 8 printf("父进程开始运行,pid: %d\n", getpid());9 pid_t id = fork();10 printf("进程开始运行,pid: %d\n", getpid());11 }
2).父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
3).fork有两个返回值
返回值中子进程为0,父进程为子进程的pid
4).fork 之后通常要用 if 进行分流
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{printf("父进程开始运行,pid: %d\n", getpid());pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id == 0){// childwhile(1){sleep(1);printf("我是一个子进程 !, 我的pid: %d, 我的父进程id: %d\n", getpid(), getppid());}} else{ //fatherwhile(1){ sleep(1);printf("我是一个父进程 !, 我的pid: %d, 我的父进程id: %d\n", getpid(), getppid());} }printf("进程开始运行,pid: %d\n", getpid());
}
那么我们会产生下面几个问题
1.fork为什么会有两个返回值?
因为 父进程 :子进程 == 1 :n 父进程可能有多个子进程,父进程需要管理子进程,所以需要得到子进程的pid,所以父进程的返回值为子进程的pid,而子进程只需要管理好自己,子进程pid可以通过getpid得到,所以返回0。
2.为什么一个函数会被返回两次?
fork语句后创建了子进程且被调度了,父进程执行一次return,子进程也执行一次return
3.一个变量怎么能让 if 和 else if 同时成立?这个问题需要在后面才能解释清楚。
首先我们要知道一个前提:进程具有独立性。也就是父进程挂掉了子进程也无影响。
代码测试:
#include <stdio.h> #include <unistd.h> #include <sys/types.h>int gval=100; int main() {printf("父进程开始运行,pid: %d\n", getpid());pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id == 0){printf("我是一个子进程 !, 我的pid: %d, 我的父进程id: %d, gval: %d\n", getpid(), getppid(), gval);sleep(5);// childwhile(1){sleep(1);printf("子进程修改变量: %d->%d", gval, gval+10);gval+=10; // 修改printf("我是一个子进程 !, 我的pid: %d, 我的父进程id: %d\n", getpid(), getppid());}}else{//fatherwhile(1){sleep(1);printf("我是一个父进程 !, 我的pid: %d, 我的父进程id: %d, gval: %d\n", getpid(), getppid(), gval); }}printf("进程开始运行,pid: %d\n", getpid()); }
二).进程状态
1.Linux内核源代码怎么说
为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。
下面的状态在kernel源代码里定义:
*
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] = {"R (running)", /*0 */"S (sleeping)", /*1 */"D (disk sleep)", /*2 */"T (stopped)", /*4 */"t (tracing stop)", /*8 */"X (dead)", /*16 */"Z (zombie)", /*32 */
}
进程状态就是一个整数
2.运行 && 阻塞 && 挂起
挂起:将进程交换到磁盘的swap分区
运行:进程在调度队列中,进程的状态都是running
阻塞:等待某种设备或资源就位(键盘,显示器,网卡....)
进程状态的变化表现之一:就是要在不同的队列中进行流动,本质都是数据结构的增删查改
3.进程状态查看
循环查看进程状态:while :; do ps axj |head -1; ps axj | grep code ;sleep 1; done
a:显示一个终端所有的进程,包括其他用户的进程。
x:显示没有控制终端的进程,例如后台运行的守护进程。
j:显示进程归属的进程组ID、会话ID、父进程ID,以及与作业控制相关的信息
u:以用户为中心的格式显示进程信息,提供进程的详细信息,如用户、CPU和内存使用情况等
我们通过代码来具体查看进程状态
R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
这个状态很少见,当磁盘老化,内存严重不足时才有可能出现
T/t停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
小 t 状态,程序被debug,断点,程序被暂停了
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
4.Z(zombie)-僵尸进程
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(僵尸)进程
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
我们使用下面这段代码查看僵尸状态
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t id = fork();if(id == 0){//childint count = 5;while(count) //5次后退出{printf("我是子进程,我正在运行: %d\n", count);sleep(1);count--;}}else {while(1){printf("我是父进程,我正在运行...\n");sleep(1);}}return 0;
}
僵尸进程危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!那么就会造成内存泄漏。
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!
- 那⼀个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存。
5.孤儿进程
父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”
孤儿进程被1号systemd进程领养,当然要有systemd进程回收喽。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t id = fork();if(id == 0){// childwhile(1){printf("我是一个子进程, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);}}else{// fatherint cnt = 5;while(cnt){printf("我是一个父进程, pid: %d, ppid: %d\n", getpid(), getppid());cnt--;sleep(1);}} return 0;
}
那么这个1号进程是什么呢? 为什么要领养呢?
1号进程就是操作系统。
如果不领养,子进程退出,进入僵尸状态后就无法回收,造成内存泄漏。
三).进程优先级
1.基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样⼀来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能
当然,这么看还是很陌生,我们从三个方向认识。
是什么?
是进程得到cpu资源的先后顺序。
为什么?
目标资源稀缺,导致要通过优先级确认谁先谁后的问题。
怎么办?
也是一种数字。值越低,优先级越高,反之,优先级越低。基于时间片的分时操作系统,考虑公平性,优先级可能变化,但是变化幅度不能太大。
2.查看系统进程
ps -al | head -1 && ps -al |grep code
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍⽣而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值
注意:
1.nice其取值范围是-20⾄19,一共40个级别 。
2.当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。
3.程真实的优先级=PRI(默认优先级80)+NI。
3.查看修改进程优先级
用top命令更改已存在进程的nice:
- top
- 进入top后按“r”‒>输⼊进程PID‒>输入nice值。注意是输入nice值。
命令 | 用途 |
---|---|
nice | 启动时设置Nice值 |
renice | 修改运行中进程的Nice值 |
chrt | 查看/设置实时优先级 |
ps -o pid,ni,pri,rtprio,comm | 查看各种优先级 |
top | 交互式查看和修改优先级 |
注意:优先级设立不合理,会导致优先级低的进程长时间得不到CPU资源,进而导致:进程饥饿
4.补充概念---竞争、独立、并行、并发
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
并发: 多个进程在⼀个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
四).进程切换
CPU上下文切换:其实际含义是任务切换, 或者CPU寄存器切换。当多任务内核决定运行另外的任务时, 它保存正在运行任务的当前状态, 也就是CPU寄存器中的全部内容。这些内容被保存在任务自己的堆栈中, 入栈工作完成后就把下一个将要运行的任务的当前状况从该任务的栈中重新装入CPU寄存器, 并开始下一个任务的运行, 这一过程就是context switch。
当然这么看还是不理解,我们先认识下几个问题 。
1.死循环进程如何运行
- 一旦一个进程占有CPU,会把自己的代码执行完吗?不会,只执行一段时间片的东西。
- 死循环进程不会一直占有CPU。
2. CPU和寄存器
3.如何切换
加速理解:
可以理解为我们进入大学后去服两年兵役,此时我们需要向导员报告,学校需要保存我们的学籍信息。两年后,我们回来继续上学,那么我们要提前通知导员,让学校恢复我们的学籍信息。我们可以粗略的认为:学校-----CPU;导员-----调度器;我们-----进程;学籍-----进程运行的临时数据,CPU内寄存器里面的内容(当前进程的上下文数据);保留学籍-----保存进程上下文数据,CPU内寄存器里面的内容保存起来;恢复数据-----恢复进程上下文数据,恢复到CPU内寄存器里;去服兵役-----进程从CPU上剥离下来。
时间片:当代计算机都是分时操作系统,没有进程都有它合适的时间片(其实就是⼀个计数器)。时间片到达,进程就被操作系统从CPU中剥离下来。
五).Linux真实的调度算法
图是Linux2.6内核中进程队列的数据结构
1.优先级
- 普通优先级:100〜139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
- 实时优先级:0〜99(不关心)
2.活动队列
- 时间片还没有结束的所有进程都按照优先级放在该队列
- nr_active: 总共有多少个运行状态的进程
- queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
- 从该结构中,选择一个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了 - bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率!
3.过期队列
- 过期队列和活动队列结构一模一样
- 过期队列上放置的进程,都是时间片耗尽的进程
- 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算
4.active指针和expired指针
- active指针永远指向活动队列
- expired指针永远指向过期队列
- 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时⼀直都存在的。
- 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!
那么我们理解了这算法,我们也就知道了为什么要有 PRI和NI两个值了,如果没有NI,那当我们修改进程的优先级时,是在活动队列直接将进程的优先级修改然后再排序吗?不,那会大大增加时间成本;而是将修改的结果计算好,当进程在活动队列运行结束后进入过期队列后直接链接,不用排序。
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值
总结: 在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法!
相关文章:
Linux 入门:操作系统进程详解
目录 一.冯诺依曼体系结构 一). 软件运行前为什么要先加载?程序运行之前在哪里? 二).理解数据流动 二.操作系统OS(Operator System) 一).概念 二).设计OS的目的 三).如何理解操作系统…...
【2025软考高级架构师】——2024年05月份真题与解析
摘要 本文内容是关于2025年软考高级架构师考试的相关资料,包含2024年05月份真题与解析。其中涉及体系结构演化的步骤、OSI协议中能提供安全服务的层次、数据库设计阶段中进行关系反规范化的环节等知识点,还提及了软考高级架构师考试的多个模块ÿ…...
Mybatis执行流程知多少
思维导图: 一、MyBatis 执行流程概述 MyBatis 的执行流程可以大致分为以下几个关键步骤:配置加载、会话创建、SQL 执行和结果处理。下面我们将逐步详细介绍每个步骤。 二、配置加载 1. 配置文件的重要性 MyBatis 的配置文件是整个框架的基础,…...
码蹄集——偶数位、四边形坐标
目录 MT1039 偶数位 MT1051 四边形坐标 MT1039 偶数位 思路:直接使用按位操作符 一个整型数字是32位,十六进制表示为0x后跟8个字符,每个字符为0-e,代表0-15; 把偶数位改为0,就是用0去&偶数位,用1去&奇数位,即0xAAAAAAAA,A代表10,1010(从右往 左依次为0位,…...
Java 中使用 Callable 创建线程的方法
一、Callable 接口概述 Callable接口位于java.util.concurrent包中,与Runnable接口类似,同样用于定义线程执行的任务,但它具有以下独特特性: 支持返回值:Callable接口声明了一个call()方法,该方法会在…...
代码随想录算法训练营Day44
力扣1045.不相交的线【medium】 力扣53.最大子数组和【medium】 力扣392.判断子序列【easy】 一、力扣1045.不相交的线【medium】 题目链接:力扣1045.不相交的线 视频链接:代码随想录 题解链接:灵茶山艾府 1、思路 和1143.最长公共子序列一…...
Java大师成长计划之第12天:性能调优与GC原理
📢 友情提示: 本文由银河易创AI(https://ai.eaigx.com)平台gpt-4o-mini模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。 在 Java 编程中,性能调优…...
【MySQL】索引(重要)
目录 一、索引本质: 索引的核心作用 索引的优缺点 二、预备知识: 硬件理解: 软件理解: MySQL与磁盘交互基本单位: 三、索引的理解: 理解page: 单个page: 多个page&#x…...
C++多态(上)
目录 一、多态的概念 二、多态的定义及实现 1. 多态的构成条件 2. 虚函数 3. 虚函数的重写 4. C11 override 和 final 4.1 final 关键字 4.2 override 关键字 5. 重载、覆盖(重写)、隐藏(重定义)的对比 三、抽象类 1. 概…...
【AI提示词】 复利效应教育专家
提示说明 一位拥有金融学和教育学背景的知识型内容创作者,擅长用简单易懂的语言向读者解释复杂概念 提示词 # Role: 复利效应教育专家## Profile - language: 中文 - description: 一位拥有金融学和教育学背景的知识型内容创作者,擅长用简单易懂的语言…...
嵌入式系统基础知识
目录 一、冯诺依曼结构与哈佛结构 (一)冯诺依曼结构 (二)哈佛架构 二、ARM存储模式 (一)大端模式 (二)小端模式 (三)混合模式 三、CISC 与 RISC &am…...
如何克服情绪拖延症?
引言 你是否也曾有过这样的经历? 明明手头有重要的工作,却总是忍不住刷手机、看视频,直到最后一刻才匆忙赶工? 你是否在心里暗暗发誓“明天一定好好干”,但第二天依旧重复着同样的拖延? 其实࿰…...
【操作系统】哲学家进餐问题
问题描述 哲学家进餐问题是并发编程中的一个经典问题,描述了五位哲学家围坐在一张圆桌旁,他们的生活由思考和进餐组成。在圆桌上有五个盘子,每位哲学家面前一个盘子,盘子之间有一支叉子。哲学家进餐需要同时使用左右两支叉子。问题…...
Kotlin协程解析
目录 一、协程的使用 二、协程的执行原理 2.1、挂起函数的反编译代码及执行分析 2.2、协程执行流程分析 2.2.1、createCoroutineUnintercepted方法 2.2.2、intercepted方法 2.2.3、resumeCancellableWith方法 2.3、Dispatcher----分发器的实现 2.3.1、Main 分发器的实…...
Nginx核心功能 02
目录 Nginx代理技术核心概念 (一)正向代理(Forward Proxy) 1. 基本定义 2. 技术原理 3. 应用场景 (二)反向代理(Reverse Proxy) 1. 基本定义 2. 技术原理 3. 应用场景 一、…...
聊聊对Mysql的理解
目录 1、Sql介绍 1.1、SQL的分类 1.2、数据库的三大范式 1.3、数据表的约束 1.4、约束的添加与删除 2、核心特性 3、主要组件 4、数据结构原理 5、索引失效 6、常用问题 7、优势与局限 前言 MySQL是一个开源的关系型数据库管理系统(RDBMS),由瑞典MySQL A…...
「Mac畅玩AIGC与多模态17」开发篇13 - 条件判断与分支跳转工作流示例
一、概述 本篇在多节点串联的基础上,进一步引入条件判断与分支跳转机制,实现根据用户输入内容动态走不同执行路径。开发人员将学习如何配置判断节点、定义分支规则,以及如何在工作流中引导执行方向,完成基础的逻辑控制。 二、环境准备 macOS 系统Dify 平台已部署并可访问…...
pycharm terminal 窗口打不开了
参考添加链接描述powershell.exe改为cmd.exe发现有一个小正方形,最大化可以看见了。...
JAVA:使用 MapStruct 实现高效对象映射的技术指南
1、简述 在 Java 开发中,对象之间的转换是一个常见的需求,尤其是在 DTO(数据传输对象)和实体类之间的转换过程中。手动编写转换代码既耗时又容易出错,而 MapStruct 是一个优秀的对象映射框架,可以通过注解生成高效的对象转换代码,从而大大提升开发效率。 本文将介绍 M…...
Linux线程深度解析:从基础到实践
Linux线程深度解析:从基础到实践 一、线程基础概念 1. 进程与线程定义 进程:一个正在运行的程序,是操作系统资源分配的最小单位(拥有独立的地址空间、文件描述符等资源),状态包括就绪、运行、阻塞。线程…...
【ROS2】launch启动文件如何集成到ROS2(Python版本)
一、简单实操 1.创建/打开一个功能包 mkdir -p my_ws/src cd my_ws/src ros2 pkg create my_pkg_example --build-type ament_python 2.创建Launch文件的存放目录 将所有启动文件都存储在launch包内的目录中。 目录结构如下所示: src/my_pkg_example/launch/…...
用 PyTorch 轻松实现 MNIST 手写数字识别
用 PyTorch 轻松实现 MNIST 手写数字识别 引言 在深度学习领域,MNIST 数据集就像是 “Hello World” 级别的经典入门项目。它包含大量手写数字图像及对应标签,非常适合新手学习如何搭建和训练神经网络模型。本文将基于 PyTorch 框架,详细拆…...
碰撞检测学习笔记
目录 SUMO 模拟碰撞 LimSim pygame模拟碰撞检测 SUMO 模拟碰撞 LimSim 多模态大语言模型(M)LLM的出现为人工智能开辟了新的途径,特别是提供增强的理解和推理能力,为自动驾驶开辟了新途径。本文介绍LimSim,LimSim的…...
Sway初体验
Sway(缩写自 SirCmpwn’s Wayland compositor[1])是一款专为 Wayland 设计的合成器,旨在与 i3 完全兼容。根据官网所述: Sway 是 Wayland 的合成器,也是 x11 的 i3 窗口管理器的替代品。它可以根据您现有的 i3 配置工作…...
《工业社会的诞生》章节
工业革命的技术前奏 早期工业技术双引擎: 【火药武器】:重塑战争形态与经济地理 新式青铜炮助力殖民扩张,开辟全球贸易网络 高桅帆船(西班牙大帆船)实现洲际航行 战争规模化倒逼中央集权,催生国家-商人…...
消息队列MQ
参考资料:https://cloud.tencent.com/developer/article/2335397 https://www.cnblogs.com/hahaha111122222/p/18457859 消息队列是大型分布式系统不可缺少的中间件,也是高并发系统的基石中间件 消息队列 消息队列 Message Queue 消息队列是利用高效可…...
LangChain4J-XiaozhiAI 项目分析报告
LangChain4J-XiaozhiAI 项目分析报告 GitHub 链接 1. 项目概述 本项目名为 “硅谷小智(医疗版)”,是一个基于 Java 技术栈和 LangChain4J 框架构建的 AI 聊天助手应用。其核心目标是利用大型语言模型(LLM)的能力&am…...
学习spring boot-拦截器Interceptor,过滤器Filter
目录 拦截器Interceptor 过滤器Filter 关于过滤器的前置知识可以参考: 过滤器在springboot项目的应用 一,使用WebfilterServletComponentScan 注解 1 创建过滤器类实现Filter接口 2 在启动类中添加 ServletComponentScan 注解 二,创建…...
【程序+论文】大规模新能源并网下的火电机组深度调峰经济调度
目录 1 主要内容 讲解重点 2 讲解视频及代码 1 主要内容 该视频为《大规模新能源并网下的火电机组深度调峰经济调度》代码讲解内容,该程序有完全对照的论文,以改进IEEE30节点作为研究对象,系统包括5个火电机组和2个新能源机组,…...
【win11 】win11 键盘测试
我的键盘是支持mac和win的,fn tab 就能切换,有可能是用错了模式,导致 我alt a 就会弹出 win11的 wifi 等菜单控制 键盘测试网站 https://keyboard.bmcx.com/ 识别到我按下的是alt...
再识动静态库
动静态库 1 手动制作静态库2 手动调用静态库方式一:(安装到系统)方式二:(和源文件一起)方式三:(使用带路径的库) 3 动态库制作与使用方式一:拷贝到系统方式二…...
前端 uni-app 初步使用指南
在数字化浪潮下,实现应用多端适配成为开发者的刚需。uni-app 凭借 “一次编写,多端运行” 的特性,极大提升了开发效率,成为前端开发的热门选择。如果你是首次接触 uni-app,这篇文章将带你开启 uni-app 的使用之旅&…...
尼卡音乐 1.1.1 | 免费畅听全网音乐,支持无损下载,无广告无需注册登录
尼卡音乐是一款可以免费畅听全网音乐的应用程序,支持免费下载无损高品质音源,并且没有任何广告,无需注册登录。用户可以轻松搜索全网无损音质音源,并可将其他音乐APP的歌单导入,让音乐陪你开心一整天。该应用彻底拒绝臃…...
33.降速提高EMC能力
降速提高EMC能力 1. 电磁兼容问题的错误累积效应2. 降速减少累积效应的机理分析 1. 电磁兼容问题的错误累积效应 2. 降速减少累积效应的机理分析 降速之后,信号的波形更完整,容错空间更大;另外边沿变缓,对外干扰也会减小。...
【赵渝强老师】TiDB的MVCC机制
TiDB是一款开源的国产分布式关系型数据库。TiKV是TiDB的行存引擎,它支持多版本并发控制(Multi-Version Concurrency Control,MVCC)。假设有这样一种场景:某客户端A在写一个Key,另一个客户端B同时在对这个Key进行读操作。如果没有数据的多版本…...
数电填空题整理(适用期末考试)
在下列门电路中,OC门能实现“线与”逻辑功能; 三态门能用于总线结构的数 据传输;传输门 能实现模拟信号的双向传输。 并联比较型A/D转换器的转换速度最快, 双积分型A/D转换器的稳定性和抗干扰能力最好 TTL与非门多余的输入端应该…...
node核心学习
目录 1-1node概述 1-2全局对象 1-3Node的模块化细节 1-4Node中的ES模块化 1-5基本内置模块 OS模块: path模块: url模块: util模块: 1-6文件IO I/O:input output fs模块的方法 代码示例: 练习…...
基于 PyQt 的YOLO目标检测可视化界面+ nuitka 打包
在人工智能和计算机视觉领域,YOLO(You Only Look Once)是一种广泛使用的实时目标检测算法。为了直观地展示YOLO算法的检测效果,我们使用Pyqt框架进行检测结果的可视化,同时为了使其能够脱离Python环境,我们…...
234树和红黑树
首先,把目光聚集在234树中 以下是234的三种节点(可以有更多这里使用以下的三个): 右侧是节点转换成红黑树节点的样子。 接下来会用以下序列进行1234树的搭建和红黑树的搭建: 首先是234树 2-3-4树(234树&…...
GenCLS++:通过联合优化SFT和RL,提升生成式大模型的分类效果
摘要:作为机器学习中的一个基础任务,文本分类在许多领域都发挥着至关重要的作用。随着大型语言模型(LLMs)的快速扩展,特别是通过强化学习(RL)的推动,对于更强大的分类器的需求也在不…...
maven坐标导入jar包时剔除不需要的内容
maven坐标导入jar包时剔除不需要的内容 问题描述解决方案 问题描述 maven坐标导入jar包时剔除不需要的内容 解决方案 Spring Boot 默认使用 Logback,需在 pom.xml 中排除其依赖: <dependency><groupId>org.springframework.boot</gro…...
Oracle OCP认证考试考点详解083系列06
题记: 本系列主要讲解Oracle OCP认证考试考点(题目),适用于19C/21C,跟着学OCP考试必过。 26. 第26题: 题目 解析及答案: 关于块介质恢复,以下哪三项是正确的? A) 需恢复一个或多个…...
llfc项目分布式服务笔记
一、系统整体架构流程图(简明版) 复制代码 +---------------+ +------------------+ +----------------+ | 客户端 (Client) |--------->| GateServer |----------| StatusServer |<--+ +---------------+ +--------------…...
“链式前向星”等三种存图方式分别输出“无向无权图”的“DFS序列”
【DFS序列】 DFS序列(深度优先搜索序列),是树或图结构在深度优先遍历过程中生成的节点访问顺序记录。 下面三段代码,分别采用链式前向星、邻接表、邻接矩阵存图,输出图的“DFS序列”。 【DFS:链式前向星】…...
Lesson 16 A polite request
Lesson 16 A polite request 词汇 park n. 公园,停车场,庄园 v. 停车,泊车 例句:让我来停车。 Let me park. 相关:spot n. 车位 区别:garden n. 花园 [小,私家的] 例句:我们…...
【IP101】边缘检测技术全解析:从Sobel到Canny的进阶之路
🌟 边缘检测的艺术 🎨 在图像处理的世界里,边缘检测就像是给图像画眉毛 —— 没有它,你的图像就像一只没有轮廓的熊猫🐼。让我们一起来探索这个神奇的"美妆"技术! 📚 目录 基础概念 …...
Nx 智能分发机制(Nx Agents + Nx Cloud)
Nx 智能分发机制(Nx Agents Nx Cloud) 阶段关键做的事作用1. 收集信息- Project Graph:解析整个 workspace 依赖关系(谁依赖谁)- 历史统计:每次 CI 结束后将每个任务的实际用时与缓存命中情况上传…...
《“昊龙一号”:开启中国航天货运新时代》
中国航天新力量:昊龙一号登场 在 2024 年 10 月 29 日上午,神舟十九号载人飞行任务新闻发布会如一颗重磅炸弹,在航天领域激起千层浪。发布会上,一系列关乎中国载人航天工程未来走向的重要信息被披露,其中,“昊龙一号” 货运航天飞机入围空间站低成本货物运输系统总体方案…...
C++ 多态:原理、实现与应用
目录 引言 一、多态的概念 二、多态的定义及实现 (一)构成条件 (二)虚函数的深入理解 (三)虚函数的重写(覆盖) 三、抽象类 (一)概念 (二&…...
多模态大语言模型arxiv论文略读(五十八)
How Does the Textual Information Affect the Retrieval of Multimodal In-Context Learning? ➡️ 论文标题:How Does the Textual Information Affect the Retrieval of Multimodal In-Context Learning? ➡️ 论文作者:Yang Luo, Zangwei Zheng, …...