【linux】进程概念详述

news2024/11/20 15:19:49

进程概念

  • 一、冯诺依曼系统
  • 二、操作系统
    • 2.1 OS层次图
    • 2.2 操作系统的意义
      • 2.2.1 系统调用与库函数的区别
    • 2.3 管理的理解
  • 三、进程
    • 3.1 进程的概念
    • 3.2 描述进程-PCB
    • 3.3 进程和程序
    • 3.4 PCB内容
      • 3.4.1 查看进程
      • 3.4.2 标识符
      • 3.4.3 状态
      • 3.4.4 程序计数器
      • 3.4.5 记账信息
      • 3.4.6 上下文信息❗️❗️
  • 四、fork系统调用创建进程
    • 4.1 fork的理解
    • 4.2 fork的返回值
  • 五、进程状态
    • 5.1 运行状态
    • 5.2 睡眠状态和休眠状态
    • 5.3 停止状态和死亡状态
      • 5.3.1 前台和后台进程
    • 5.4 僵尸进程
    • 5.5 孤儿进程
  • 六、进程优先级
    • 6.1 查看优先级
    • 6.2 调整优先级
    • 6.3 并行与并发
  • 七、环境变量
    • 7.1 环境变量的定义
    • 7.2 环境变量的操作
    • 7.3 命令行参数
    • 7.4 获取环境变量
    • 7.5 环境变量的全局属性
  • 八、程序地址空间❗️❗️
    • 8.1 物理地址or虚拟地址?
    • 8.2 进程地址空间
    • 8.3 页表+MMU
    • 8.4 地址空间的好处

一、冯诺依曼系统

在这里插入图片描述

输入设备: 键盘、磁盘、网卡、显卡、写字板、摄像头等
输出设备: 显示器、磁盘、网卡、显卡等
存储器: 内存
运算器和控制器: CPU

我们可以看到输入设备和输出设备并不是完全独立的。比如我们以前的文件操作是从磁盘中读取
为什么能直接把外设的数据加载到CPU中?

因为CPU的速度远大于输入设备,如果直接把外设的数据加载进来,那么决定程序的效率就取决于外设。现在CPU直接和内存打交道,所以在没有软件优化的情况下,硬件体系结构的效率由内存决定,内存是体系结构的核心设备

现在大部分的体系结构都是冯诺依曼体系,比如我们的电脑和使用的服务器。

二、操作系统

首先要知道,启动的操作系统才有意义,就是只有把操作系统加载到内存中才有意义。

2.1 OS层次图

在这里插入图片描述

2.2 操作系统的意义

如果没有操作系统,我们就要和一堆的硬件直接接触,需要了解各种硬件的特性,使用成本太高。
由此就有了操作系统:

像这种任何计算机包含的一种最基本的能够进行软硬交互的一款软件,我们把它叫做操作系统(英文缩写OS)

OS包括:

内核:进程管理,内存管理,文件管理,驱动管理:这是OS用于管理硬件的
其它程序:函数库,shell程序等,这些程序能帮助用户更方便的使用OS

操作系统是什么?
是一款专门针对软硬件资源管理工作的软件。

操作系统的功能:
对下管理好软硬件资源
对上为用户提供稳定、高效、安全的运行环境

那OS怎么对用户提供各种功能?

首先要知道OS不信任任何用户,所以我们也只能通过接口来与OS打交道,也就是OS层次图中的系统调用接口。

2.2.1 系统调用与库函数的区别

系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,一些大佬对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。

2.3 管理的理解

既然是管理,那么就有管理者和被管理者。

我们可以想象在学校中,校长就是管理者,但是我们从来没见过校长。
管理者和被管理者不直接接触,管理者的决策交给执行者(老师、辅导员),通过他们管理被管理者(学生)。
按照上面OS的层次图,OS就是校长,驱动程序就是辅导员,底层硬件就是我们学生。

通过例子我们可以得出以下的结论:

1️⃣ 管理者和被管理者并不直接打交道
2️⃣ 如何对被管理者进行管理?先进行一些决策,再把这些决策施行

而管理者的决策需要有依据,依据就是数据

而我们的数据怎么被管理者知道呢?
如果一个学校人很少,校长有可能能知道每个人的数据,但是如果人很多呢?该如何聚合这些数据呢?

在C语言中,我们可以使用结构体,在C++中,就使用类。

这个过程,我们通常叫做数据的描述

而如何将这些聚合数据产生关联呢?

可以采用一些数据结构存储,由此变成数据结构的增删查改。

这个过程,我们通常叫做数据的组织

由此我们得出重要结论:
计算机执行管理时,先把管理对象描述起来,再把管理对象组织起来

以上讲的都是对硬件的管理,那么对软件呢?

三、进程

3.1 进程的概念

进程=程序对应的文件内容(struct)+相关数据结构(比如优先级队列)

在Windows中任务管理器下的程序就叫进程。

上面我们说过操作系统的本质是管理,而管理是先描述再组织。
所以在进程形成的时候,操作系统会对该进程创建PCB(进程控制块)

3.2 描述进程-PCB

PCB其实是一个结构体,包含进程的所有属性信息,在linux中,PCB就是
struct task_struct{};而这两个的关系可以类比类和对象之间的关系。

task_ struct内容分类

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

操作系统要找找到进程,不是找进程加载到内存的代码数据,是直接找PCB。
在这里插入图片描述
有了进程控制块,所有的进程管理与进程对应的程序毫无关系与进程对应的PCB强相关

3.3 进程和程序

我们写好了程序,当程序被加载到内存中时,操作系统会创建一个task_struct来描述程序,我们把task_struct 和加载到内存的可执行程序一起叫做进程
也就是上面说的:进程=程序对应的文件内容(struct)+ 相关数据结构(比如优先级队列)

3.4 PCB内容

3.4.1 查看进程

查看进程
先写一个死循环的程序:
在这里插入图片描述
查看进程指令:
有两种指令:

ps axj | grep “mytest”
ps -l查看运行中进程的详细信息

运行后打开新的对话框:

在这里插入图片描述
另一种查看进程的方法:

ls /proc

proc是linux默认查看进程的目录,而我们创建的的进程的信息也会再proc中创建一个目录。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

pid在后面会讲

3.4.2 标识符

查看进程的标识符:
getpid()

在这里插入图片描述
运行后:
在这里插入图片描述
在这里插入图片描述

查看父进程的标识符:
getppid()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4.3 状态

退出信号:
我们写的程序末尾会有个return 0,0就是退出码

查看最近一次的退出码:
echo $?

在这里插入图片描述
在这里插入图片描述

3.4.4 程序计数器

永远指向将被执行的下一行指令的地址。
在这里插入图片描述

3.4.5 记账信息

OS有一个调度模块,可以较为均匀的调度每个进程,因为进程要获得CPU的资源才能进行,而进程又有很多。他会记录每个进程所使用的时间总和以确保“公平”。

3.4.6 上下文信息❗️❗️

假设有三个进程正在运行:
在这里插入图片描述
为了保证公平,操作系统规定了进程单次运行的时间片(单次运行的最长时间),我们以为CPU在同时运行多个进程,其实是CPU的快速切换完成的
但是进程很有可能没运行完,此时PCB1就拍到了末尾。
在这里插入图片描述
进程运行会产生大量的临时数据
但是这样就会引出一个问题:
当PCB1运行完一次时间片后这些临时数据下次还要用,如果不管,PCB2就会覆盖掉PCB1的临时数据。

所以我们需要保护上下文信息和恢复上下文信息,当PCB1运行完一个时间片时,PCB1带走自己的临时数据,PCB回来的时候,再把临时数据给寄存器,接着上次运行。

四、fork系统调用创建进程

4.1 fork的理解

在这里插入图片描述
在这里插入图片描述
那么如何理解fork创建子进程呢?
首先要知道创建进程的三种方式:

1️⃣ 运行程序
2️⃣ 执行命令
3️⃣ fork
在操作系统的角度,这三种方式没有差别

fork的本质是创建一个进程,而这个进程就是task_struct + 进程的代码和数据task_struct是一创建进程就有的,但是进程的代码和数据怎么办?

默认情况下会继承父进程的代码,而且task_struct也会以父进程为模板,初始化子进程的task_struct(上下文信息也会继承,所以子进程fork前的代码不会运行),要注意代码是不可修改的(只读)。

而数据默认情况下也是共享的,但是要考虑修改的情况,如果一个进程发生修改,就会发生写时拷贝。

写时拷贝:

进程具有独立性,当一个进程的数据发生修改,为了不让另一个进程也被改变,所以会拷贝一份数据再修改。
好处:提高效率(不修改就共享)

4.2 fork的返回值

经过上述描述,我们会想到一个问题:
如果只掉用fork,父子就做同一件事,这有意义吗?

答案是没有意义,所以我们需要让他们做不一样的事情。

那么怎么让他们做不一样的事情呢?

答案时依靠返回值

fork的返回值:

失败:返回 < 0
成功:
1️⃣ 给父进程返回子进程的pid
2️⃣ 给子进程返回0

在这里插入图片描述
在这里插入图片描述
如何理解有两个返回值?

pid_t fork()
{
	……
	return ……
}

当fork的时候,就会分流,而当一个进程return的时候就会写入数据,发生写时拷贝,导致两个不同的返回值。

为什么要如此设置两个返回值?

父进程有很多子进程,子进程只有一个父进程,所以父进程要找到子进程就需要子进程的pid,子进程就不需要。

补充一点:

fork后父子进程执行顺序不确定

五、进程状态

首先想想为什么要有进程状态?

进程状态可以方便OS快速判断进程的状态,方便使其完成各种功能,本质是一种分类

linux中的进程一般有以下状态:

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列
里。
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
(interruptible sleep))。
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的
进程通常会等待IO的结束。
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

5.1 运行状态

在这里插入图片描述

前面我们讲过进程在运行状态不一定占有CPU,而是运行一个时间片后让下一个进程获得CPU资源。
只要在运行队列中,所有的状态都叫做R状态,随时被CPU调用。

在这里插入图片描述
在这里插入图片描述

5.2 睡眠状态和休眠状态

如果一个程序需要的资源没有准备好,那么程序将会睡眠,等待资源准备就绪了它才会再次运行
在这里插入图片描述
假如当程序需要读取磁盘时,此时已经已经有多个进程在等待,这是就会形成等待队列,就是S(睡眠)或者D(休眠)状态。

总结一下:

等CPU资源的队列叫运行队列
等外设资源的队列叫等待队列
当PCB1一旦获取磁盘资源,就会把PCB1的状态改成R(被唤醒),放入运行队列中,等到他获取CPU资源的时候,再读取磁盘。
从运行队列到等待队列叫做挂起等待(阻塞),从等待队列到运行队列叫唤醒进程

一个进程可能因为运行的需要,在不同的队列里,每个队列代表不同的运行状态。

那么睡眠状态(S)和休眠状态(D)有什么区别呢?

S是浅度睡眠,是可以中断的
D是深度睡眠,不可中断

为什么要有两种“睡眠”状态?

当一个进程想要往磁盘写入数据,写入磁盘需要时间,此时该进程就在内存等待结果(处于休眠状态),如果此时可用资源比较少,该进程就会被OS杀死,那么磁盘写入结果的返回就无法送达,可能引发问题,但是如果是D状态,OS也无法杀死

在这里插入图片描述
在这里插入图片描述
为什么数据刷新这么快,还是S状态?

上面说过了写入磁盘需要时间,而CPU的速度太快了(比IO快得多),所以我们以为他一直在执行,其实它大部分时间在休眠

5.3 停止状态和死亡状态

停止状态跟S状态很像,都可以挂起进程,那么他们有什么区别呢?

S状态虽然什么事都没干,但会更新核心数据,比方说我们写了个sleep(10);到了10秒就会唤醒该进程。
而T状态就是彻底暂停,不会更新数据。

kill -19 可以暂停进程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

kill -18 可以继续进程

在这里插入图片描述

死亡状态(X):
我们在创建进程的时候会有PCB和代码和数据,当进程死亡的时候,也要把这些资源回收回去。

kill -9 可以杀死进程

在这里插入图片描述
在这里插入图片描述

5.3.1 前台和后台进程

我们看到他们的状态有的后面带+号有的不带,这表示什么呢?
后面带+号表示前台进程
后面不带+号表示后台进程

区别就是
前台进程运行时我们无法输入任何指令,但可以「Ctrl」+ c干掉进程
而后台进程运行的时候可以执行命令,但是「Ctrl」+ c不能干掉进程,想要杀死就用kill -9。

5.4 僵尸进程

上面我们说了进程需要退出时,系统会回收这个进程的资源,然后进程就进入了死亡。
但是当进程退出的时候,进程的所有资源不会立即回收,而是进入僵尸状态(Z),把数据暂时保存(要写入退出信息),目的是为了判断退出死亡的原因

资源是由父进程进行回收。

验证:我们可以让父进程休息,然后杀死子进程就可以看到僵尸状态。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
僵尸进程我们需要尽量避免,因为会导致过度占用空间和内存泄漏

5.5 孤儿进程

字面意思,父子进程同时运行,父进程被杀掉,子进程就变成了孤儿进程。
孤儿进程将会被1号进程(OS本身)领养

在这里插入图片描述

六、进程优先级

首先要知道为什么有优先级,本质是因为资源过少。
优先级也是PCB中的一个数据。
它决定了程序获得CPU资源的顺序。

6.1 查看优先级

ps指令
ps指令主要用来显示linux进程信息
选项:

-a 显示所有进程

在这里插入图片描述

PRI :代表这个进程可被执行的优先级,其值越小越早被执行,默认值为80
NI :优先级修正数据,取值范围(-20 ~ 19)

PRI的最终值也取决于NI值(PRI=80+NI)

6.2 调整优先级

调整优先级其实就是调整NI值。

输入top后按r->输入进程pid->输入nice

在这里插入图片描述
我们知道NI的范围只能是-20 ~ 19,那么为什么不让范围更大呢?

优先级不管怎么调也只是相对的优先,不能出现绝对的优先,不然会让一些进程一直得不到资源,形成饥饿问题。

6.3 并行与并发

并行:

多个进程在多个CPU下分别,同时进行运行,就是在任意时刻都有两个以上的进程在运行,这称之为并行

并发:

多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

七、环境变量

为什么我们运行自己的程序的时候要加上././就是指明当前路径,要找到程序才能运行,而我们运行指令的时候却不用加呢?

因为环境变量

7.1 环境变量的定义

环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性(这就是我们使用某些程序不需要./的原因)

要注意他也是OS在内存中开辟的空间用来保存数据。

常见的环境变量:

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。

7.2 环境变量的操作

在这里插入图片描述
env命令可以查看系统所有变量
在这里插入图片描述

我们也可以把我们自己的程序路径加到环境变量中

使用export指令:

export PATH=

在这里插入图片描述
此时我们就可以像运行指令一样运行我们自己的程序:
在这里插入图片描述
但此时我们发现我们使用不了正常的指令了
在这里插入图片描述
再查看环境变量:
在这里插入图片描述
可以看到原来的被覆盖了。
所以我们添加环境变量不覆盖应该使用:

export PATH=$PATH:

在这里插入图片描述

7.3 命令行参数

main函数可以携带两个参数:

int main(int argc, char* argv[])

argc就是参数的个数
第二个参数就是我们传进去的参数,在linux中,通常以每个程序后面的附加选项实现,例如ls -a, ls -l

在这里插入图片描述
在这里插入图片描述
所以我们知道argv的图:
在这里插入图片描述
从这里我们也就知道命令行后面附加的参数是如何起作用的了。

7.4 获取环境变量

上面说过ls -al这种命令因为有环境变量可以不带路径执行,那么他是怎么得到环境变量的呢?
main函数可以携带第三个参数:char* env[] 它可以从父进程中得到。
上面讲的argv指向的是一个个的参数,而env指向的是一个个的环境变量。
在这里插入图片描述
而且我们也可以把它打印出来:
在这里插入图片描述
在这里插入图片描述
可以参考上面的env命令,发现他们一摸一样。

当然我们也可以通过系统调用获得环境变量:

getenv()

在这里插入图片描述

在这里插入图片描述

7.5 环境变量的全局属性

环境变量通常具有全局属性,可以被子进程继承下去

创建一个本地变量:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

导出环境变量:
在这里插入图片描述
在这里插入图片描述

八、程序地址空间❗️❗️

8.1 物理地址or虚拟地址?

在我们以前学到的内存布局应该是这样的:
在这里插入图片描述
但是这是真实的物理内存吗?
现在我们可以编写一段代码验证一下:
在这里插入图片描述
在这里插入图片描述
这里因为父子进程公用代码和数据,结果正常。
但是当父进程发生写时拷贝时:
在这里插入图片描述
在这里插入图片描述
我们发现他们的地址没有变化
前面我们讲过如果发生写时拷贝,就会另外开一份空间来存储数据,那么地址肯定会变化。
这只能说明打印的地址不是真实的物理地址。
我们把这个叫做虚拟地址,我们在语言层面下看到的地址,其实全部都是虚拟地址!

8.2 进程地址空间

OS中有物理地址,而每个进程都有自己的虚拟地址
每个进程都会认为自己是独享整个物理地址,它们都会以统一的方式划分自己的内存。

而每个进程都有自己的地址空间,而操作系统需要管理这些地址空间。
进程地址空间本质是内核的数据类型(struct mm_struct),类似于我们前面讲的PCB。

结构体的模拟如下:

struct mm_struct
{
	unsigned int stack_begin;
	unsigned int stack_end;
	//栈区的界限
	
	unsigned int heap_begin;
	unsigned int heap_end;
	//堆区的界限
//其他区域也类似
}

通过这些区域划分出不同的界限。每个进程都认为自己的mm_struct代表整个内存(地址从0x000000…000 ~ 0xFFFFFF…FFF),也就是每个进程都认为自己拥有4GB的空间。

但是光有虚拟地址是不够用的,必须要把数据存储在物理内存中。

8.3 页表+MMU

OS通过页表+MMU(内置在CPU中的一个硬件)来对齐进行映射
页表负责把虚拟地址映射到物理地址

那么为什么需要页表映射,不能直接让进程地址空间访问物理内存吗?

如果我们允许进程直接访问物理内存,就很有可能访问到不属于自己的空间,所以我们需要页表来管理,如果是非法的OS就直接可以拒绝访问。

举个例子
const char* p = "abcd",我们不能通过指针p修改"abcd",因为它在字符常量区。本质是OS给我们的权限只有读权限(通过页表的权限管理)

8.4 地址空间的好处

我们想象一种场景:我们直接申请一块大空间,操作系统会直接全部给我了吗?如果我们没有用那么多,其他的空间不是被浪费了吗?

所以当我们在堆区申请一块空间的时候,OS会把地址空间中的heap_end加上我们申请的大小,但是却没给我们物理内存,当我们需要读取的时候,才会使用页表进行映射,得到物理空间。

假设没有地址空间,那么CPU是不是只能遍历一遍物理空间才能找到该进程的起始位置?

所以我们可以把main函数的地址放入每个进程的地址空间(同一位置),然后CPU就访问地址空间的固定位置然后通过页表映射找到物理内存存放代码数据的位置。

总结一下:
为什么要有地址空间?

1️⃣ 通过添加一层软件层,完成对进程操作的风险管理(权限管理),保护了物理内存以及各个进程的数据安全。
2️⃣ 将内存申请和内存使用的概念在时间层面上划分清楚,通过地址空间完成屏蔽底层申请物理空间的过程。达到进程读写内存和OS进行内存管理操作,在软件层面上分离(你不知OS给你的内存是富裕或者是快满状态的空间)。
3️⃣ 站在CPU和应用层的角度,每个进程可以看作统一使用4GB空间,而且每个空间区域的相对位置是比较确定的。

不管代码数据在内存如何存放,在地址空间中一定是连续存放的,大大减小了内存管理的负担。
通过以上的学习,我们再来谈程序和进程的区别:

进程是需要PCB进程地址空间页表代码数据结合起来才叫进程。

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

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

相关文章

1.极限与连续-——“机器学习中的数学”

1.通过集合相等来讲解什么是映射关系 上面问的这个问题&#xff08;2N N2&#xff09;说明了什么&#xff1f; ——两个无穷集合&#xff0c;如果能找到一种对应关系&#xff08;映射关系&#xff09;&#xff0c;那么我们就可以说这两个集合是等价的。 数列的极限就是趋势 …

字符串转二叉树

一. 题目介绍 二. 题目分析 首先 题目让我们以先序遍历的方式用字符串建立一个二叉树 输入是一个字符串 输出是是以中序遍历二叉树打印 我们先来看最简单的输入 这里只要建立一个字符数组 然后等测试用例输入就好了 // 接受输入值char arr[100]{0};scanf("%s",…

网络原理 --- 传输层Ⅳ TCP协议中的延迟应答、捎带应答、面向字节流、TCP中的异常处理

文章目录网络原理传输层TCP协议7.延迟应答8.捎带应答9. 面向字节流10.TCP中的异常处理总结网络原理 介绍TCP/IP协议中每一层里面的核心内容~ 应用层传输层网络层数据链路层物理层 传输层TCP协议 7.延迟应答 提高传输效率的机制 又是基于流量控制,来引入的提高效率的机制 实…

数据在内存中的存储

目录 数据在内存中的存储&#xff1a;&#xff1a; 整型及其浮点型存储方式: 1.数据类型介绍 2.整形在内存中的存储&#xff1a;原码 反码 补码 3.大小端字节序介绍及判断 4.浮点型在内存中的存储 5.两道经典指针选择题 C语言编程训练(牛客网) 1.喝汽水问题 2.字符串逆序 3.打…

Python编程运算符 ——算数运算符

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.运算符 1.在Python运算符中分为 2.算数运算符 3.比较重要的运算符 4…

网络原理——No.1 传输层_TCP的确认应答机制与超时重传

JavaEE传送门JavaEE JavaEE——网络原理_应用层 网络原理——传输层_UDP 目录传输层TCPTCP 的基本特性确认应答机制超时重传传输层 端到端之间的传输, 重点关注的是起点和终点 核心的协议有两个: UDP: 无连接, 不可靠传输,面向数据报, 全双工 TCP: 有链接, 可靠传输, 面向字…

黑猫带你学UFS协议第11篇:什么是逻辑单元(LU)与逻辑块(Sector)

本文依据UFS3.1 JEDEC协议及个人工作经验整理而成,如有错误请留言。 文章为个人辛苦整理,付费内容,已加入原创维权,禁止私自转载。 文章所在专栏:《黑猫带你学:UFS协议详解》 1 LU简介 我们对与UFS、emmc一类存储芯片,最重要的功能是什么?无非就是存数据和取出数据,也…

神经网络的输入稀疏矩阵,神经网络中的矩阵运算

1、BP神经网络模型各个参数的选取问题 样本变量不需要那么多&#xff0c;因为神经网络的信息存储能力有限&#xff0c;过多的样本会造成一些有用的信息被丢弃。如果样本数量过多&#xff0c;应增加隐层节点数或隐层数目&#xff0c;才能增强学习能力。 一、隐层数 一般认为&am…

牛客前端刷题(九)—— 打包篇

还在担心面试不通过吗&#xff1f;给大家推荐一个超级好用的刷面试题神器&#xff1a;牛客网&#xff0c;里面涵盖了各个领域的面试题库&#xff0c;还有大厂真题哦&#xff01; 赶快悄悄的努力起来吧&#xff0c;不苒在这里衷心祝愿各位大佬都能顺利通过面试。 面试专栏分享&a…

greenplum 源码解析 FTS辅助进程--ReadMe

简介 在greenplum数据库中master节点有一个专属进程Fault Tolerance Service (FTS: 容错服务)&#xff0c;其主要功能是检测所有segment节点的健康信息&#xff0c;如果其检测到segment节点的primary出现异常[硬件故障/宕机]&#xff0c;会在第一时间将其对应的mirror提升为新的…

MySql(50)MySQL日志

文章目录MySQL支持的日志日志类型日志的弊端慢查询日志(slow query log)通用查询日志查看当前状态启动日志永久启动临时启动查看日志删除\刷新日志错误日志(error log)删除\刷新日志二进制日志(bin log)查看默认情况日志参数设置查看日志使用日志恢复数据删除二进制日志PURGE M…

vue3 响应式对象的 api ,你全用过了吗?

文章目录Ⅰ. ref、reactive ( 递归监听 )Ⅱ. isRef、isReactive ( 判断 )Ⅲ. toRef 和 toRefs ( 解构 )Ⅳ. toRaw 、 markRaw ( 解除代理)Ⅴ. unref ( 拷贝 )Ⅵ. shallowRef 、shallowReactive&#xff08; 非递归监听 &#xff09;Ⅶ. triggerRef &#xff08;强制更新&#x…

红黑树原理及旋转

红黑树&#xff0c;本质上来说就是一棵二叉查找树 但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡 保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n) 但它是如何保证一棵n个结点的红黑树的高度始终保持在h logn的呢&#xff1f;这就引出了红黑…

相似度_对抗学习:SimCSE: Simple Contrastive Learning of Sentence Embeddings

SimCSE: Simple Contrastive Learning of Sentence Embeddings 这篇论文&#xff0c;我觉得有意思。在创造对抗学习的正负例时&#xff0c;正例直接使用它本身。将同一个句子传递给预先训练好的编码器两次&#xff1a;通过应用两次dropout&#xff0c;我们可以得到两个不同的嵌…

云计算基础:云计算越来越广泛,我们应该如何去学习云计算

随着时代的发展&#xff0c;云计算越来越普及&#xff0c;越大众化&#xff0c;使用的人越来越多&#xff0c;我们应该如何去学习这门技术呢?这篇文章我们就来介绍如何学习我们的云计算。 学前介绍&#xff1a; 学前介绍 学习资料&#xff1a;HedEX Lite、产品文档、笔记、P…

非科班程序员被裁员后反而涨薪了200%,这两个月他都经历了哪些?

今年年初开始&#xff0c;裁员潮一浪接着一浪翻滚而来&#xff0c;让互联网人胆颤心惊&#xff0c;时刻担心下一波裁员是否就要降临到自己身上。 小帅&#xff08;化名&#xff09;是一个原本月薪8k&#xff0c;在小外包公司做政府项目的一名普通员工&#xff0c;前不久就被裁员…

数据仓库建模(四):维度表的设计

数据仓库建模&#xff08;四&#xff09;&#xff1a;维度表的设计一、维度表的整体结构1.1 维度表的结构设计1.2 维度代理键1.3 自然键、超久键和超自然键1.4 下钻与上卷1.5 维度退化1.6 非规范化的扁平维度1.7 多层次维度1.8 维度属性的标识与状态信息1.9 维度表中的空值属性…

趣学算法(2)

14天阅读挑战赛 目录前言一 几类时间复杂度二 兔子数列1.问题分析2.方法13.方法24.方法3最后前言 这篇文章是《趣学算法》的读书笔记&#xff0c;也对数据结构与算法的初步介绍&#xff0c;阅读这篇文章&#xff0c;我会带你改进一个算法。 一 几类时间复杂度 常见的算法时间复…

Vue项目的记录(十三)

1.登录注册静态组件 assets这个文件夹放所有的组件公用的静态资源 在样式当中也可以使用符号&#xff0c;&#xff08;src目录的别名&#xff09;&#xff0c;要注意的是在前面你加上~ 2.注册业务 这里的验证码&#xff0c;正常来说应该是要后台发送到用户手机上&#xff0c…

拓端tecdat|R语言辅导配对检验分析案例

全文链接&#xff1a;http://tecdat.cn/?p3424 原文出处&#xff1a;拓端数据部落公众号 什么是检验对&#xff1f; 检验对的形式 &#xff08;x1&#xff0c;x2&#xff09; 出现在两种情况中&#xff1a; 对同一实体执行两次测量。例如&#xff0c;一项评估新型胰岛素疗效…