Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.MD

计算机组成原理

计算机原码,反码,补码

原码:

是最简单的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的二进制的绝对值。
若以带符号位的四位二进值数为例: 
    1010 : 最高位为‘1’,表示这是一个负数,其他三位为‘010’,
    即(0*2^2)+(1*2^1)+(0*2^0)=2(‘^’表示幂运算符)
    所以1010表示十进制数(-2)。

反码:

正数的反码还是等于原码;
负数的反码就是他的原码除符号位外,按位取反。
若以带符号位的四位二进制数为例:
    3是正数,反码与原码相同,则可以表示为0011
    -3的原码是1011,符号位保持不变,低三位(011)按位取反得(100)
    所以-3的反码为1100

补码:

正数的补码等于他的原码,
负数的补码等于反码+1。
若以带符号位的四位二进制数为例:
    3是正数,反码与原码相同,则可以表示为0011
    -3的原码是1011,符号位保持不变,低三位(011)按位取反得(100)
    所以-3的反码为1100

补码:

正数的补码等于他的原码,
负数的补码等于反码+1。

用户空间和内核空间

Kernel space 是 Linux 内核的运行空间,User space 是用户程序的运行空间。为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。
Kernel space 可以执行任意命令,调用系统的一切资源;User space 只能执行简单的运算,不能直接调用系统资源,必须通过系统接口(又称 system call),才能向内核发出指令。通过系统接口,进程可以从用户空间切换到内核空间。

top命令

第一项24.8 us(user 的缩写)就是 CPU 消耗在 User space 的时间百分比,
第二项0.5 sy(system 的缩写)是消耗在 Kernel space 的时间百分比。
ni:niceness 的缩写,CPU 消耗在 nice 进程(低优先级)的时间百分比
id:idle 的缩写,CPU 消耗在闲置进程的时间百分比,这个值越低,表示 CPU 越忙
wa:wait 的缩写,CPU 等待外部 I/O 的时间百分比,这段时间 CPU 不能干其他事,但是也没有执行运算,这个值太高就说明外部设备有问题
hi:hardware interrupt 的缩写,CPU 响应硬件中断请求的时间百分比
si:software interrupt 的缩写,CPU 响应软件中断请求的时间百分比
st:stole time 的缩写,该项指标只对虚拟机有效,表示分配给当前虚拟机的 CPU 时间之中,被同一台物理机上的其他虚拟机偷走的时间百分比

PIO与DMA

  • PIO 我们拿磁盘来说,很早以前,磁盘和内存之间的数据传输是需要CPU控制的,也就是说如果我们读取磁盘文件到内存中,数据要经过CPU存储转发,这种方式称为PIO。显然这种方式非常不合理,需要占用大量的CPU时间来读取文件,造成文件访问时系统几乎停止响应。
  • DMA(直接内存访问,Direct Memory Access)取代了PIO,它可以不经过CPU而直接进行磁盘和内存(内核空间)的数据交换。在DMA模式下,CPU只需要向DMA控制器下达指令,让DMA控制器来处理数据的传送即可,DMA控制器通过系统总线来传输数据,传送完毕再通知CPU,这样就在很大程度上降低了CPU占有率,大大节省了系统资源,而它的传输速度与PIO的差异其实并不十分明显,因为这主要取决于慢速设备的速度。

缓存IO和直接IO

缓存IO:数据从磁盘先通过DMA copy到内核空间,再从内核空间通过cpu copy到用户空间
直接IO:数据从磁盘通过DMA copy到用户空间

缓存IO

  • 读操作 :操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回;否则从磁盘中读取,然后缓存在操作系统的缓存中。
  • 写操作:将数据从用户空间复制到内核空间的缓存中。这时对用户程序来说写操作就已经完成,至于什么时候再写到磁盘中由操作系统决定,除非显示地调用了sync同步命令
缓存I/O的优点:
1)在一定程度上分离了内核空间和用户空间,保护系统本身的运行安全;
2)可以减少读盘的次数,从而提高性能。  
缓存I/O的缺点:
在缓存 I/O 机制中,DMA 方式可以将数据直接从磁盘读到页缓存中,或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输,这样,数据在传输过程中需要在应用程序地址空间(用户空间)和缓存(内核空间)之间进行多次数据拷贝操作,这些数据拷贝操作所带来的CPU以及内存开销是非常大的。

直接IO

直接IO就是应用程序直接访问磁盘数据,而不经过内核缓冲区,也就是绕过内核缓冲区,自己管理I/O缓存区,这样做的目的是减少一次从内核缓冲区到用户程序缓存的数据复制。
引入内核缓冲区的目的在于提高磁盘文件的访问性能,因为当进程需要读取磁盘文件时,如果文件内容已经在内核缓冲区中,那么就不需要再次访问磁盘;而当进程需要向文件中写入数据时,实际上只是写到了内核缓冲区便告诉进程已经写成功,而真正写入磁盘是通过一定的策略进行延迟的。然而,对于一些较复杂的应用,比如数据库服务器,它们为了充分提高性能,希望绕过内核缓冲区,由自己在用户态空间实现并管理I/O缓冲区,包括缓存机制和写延迟机制等,以支持独特的查询机制,比如数据库可以根据更加合理的策略来提高查询缓存命中率。另一方面,绕过内核缓冲区也可以减少系统内存的开销,因为内核缓冲区本身就在使用系统内存。
应用程序直接访问磁盘数据,不经过操作系统内核数据缓冲区,这样做的目的是减少一次从内核缓冲区到用户程序缓存的数据复制。这种方式通常是在对数据的缓存管理由应用程序实现的数据库管理系统中。
直接I/O的缺点就是如果访问的数据不在应用程序缓存中,那么每次数据都会直接从磁盘进行加载,这种直接加载会非常缓慢。通常直接I/O跟异步I/O结合使用会得到较好的性能。  

磁盘IO

当应用程序调用read接口时,操作系统检查在内核的高速缓存有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回,如果没有,则从磁盘中读取,然后缓存在操作系统的缓存中。应用程序调用write接口时,将数据从用户地址空间复制到内核地址空间的缓存中,这时对用户程序来说,写操作已经完成,至于什么时候再写到磁盘中,由操作系统决定,除非显示调用了sync同步命令。

网络IO

1)操作系统将数据从磁盘复制到操作系统内核的页缓存中 
2)应用将数据从内核缓存复制到应用的缓存中 
3)应用将数据写回内核的Socket缓存中 
4)操作系统将数据从Socket缓存区复制到网卡缓存,然后将其通过网络发出
  • 1、当调用read系统调用时,通过DMA(Direct Memory Access)将数据copy到内核模式
  • 2、然后由CPU控制将内核模式数据copy到用户模式下的 buffer中
  • 3、read调用完成后,write调用首先将用户模式下 buffer中的数据copy到内核模式下的socket buffer中
  • 4、最后通过DMA copy将内核模式下的socket buffer中的数据copy到网卡设备中传送。

磁盘IO和网络IO对比

磁盘IO主要的延时是由(以15000rpm硬盘为例): 机械转动延时(机械磁盘的主要性能瓶颈,平均为2ms) + 寻址延时(2~3ms) + 块传输延时(一般4k每块,40m/s的传输速度,延时一般为0.1ms) 决定。(平均为5ms)
而网络IO主要延是由: 服务器响应延时 + 带宽限制 + 网络延时 + 跳转路由延时 + 本地接收延时 决定。(一般为几十到几千毫秒,受环境干扰极大)
所以两者一般来说网络IO延时要大于磁盘IO的延时。

同步IO和异步IO

指的是用户空间和内核空间数据交互的方式
* 同步:用户空间要的数据,必须等到内核空间给它才做其他事情
* 异步:用户空间要的数据,不需要等到内核空间给它,才做其他事情。内核空间会异步通知用户进程,并把数据直接给到用户空间。

阻塞IO和非阻塞IO

指的是用户就和内核空间IO操作的方式
* 堵塞:用户空间通过系统调用(systemcall)和内核空间发送IO操作时,该调用是堵塞的
* 非堵塞:用户空间通过系统调用(systemcall)和内核空间发送IO操作时,该调用是不堵塞的,直接返回的,只是返回时,可能没有数据而已

Reactor模式

Reactor模式主要包含下面几部分内容:
* 初始事件分发器(Initialization Dispatcher):用于管理Event Handler,定义注册、移除EventHandler等。它还作为Reactor模式的入口调用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,当阻塞等待返回时,根据事件发生的Handle将其分发给对应的Event Handler处理,即回调EventHandler中的handle_event()方法
* 同步(多路)事件分离器(Synchronous Event Demultiplexer):无限循环等待新事件的到来,一旦发现有新的事件到来,就会通知初始事件分发器去调取特定的事件处理器。
* 系统处理程序(Handles):操作系统中的句柄,是对资源在操作系统层面上的一种抽象,它可以是打开的文件、一个连接(Socket)、Timer等。由于Reactor模式一般使用在网络编程中,因而这里一般指SocketHandle,即一个网络连接(Connection,在Java NIO中的Channel)。这个Channel注册到Synchronous Event Demultiplexer中,以监听Handle中发生的事件,对ServerSocketChannnel可以是CONNECT事件,对SocketChannel可以是READ、WRITE、CLOSE事件等。
* 事件处理器(Event Handler): 定义事件处理方法,以供Initialization Dispatcher回调使用。

Reactor包含如下角色:

  • Handle 句柄;用来标识socket连接或是打开文件;
  • Synchronous Event Demultiplexer:同步事件多路分解器:由操作系统内核实现的一个函数;用于阻塞等待发生在句柄集合上的一个或多个事件;(如select/epoll;)
  • Event Handler:事件处理接口Concrete Event Handler A:实现应用程序所提供的特定事件处理逻辑;
  • Reactor:反应器,定义一个接口,实现以下功能: 1)供应用程序注册和删除关注的事件句柄; 2)运行事件循环; 3)有就绪事件到来时,分发事件到之前注册的回调函数上处理;
  • Initiation Dispatcher:用于管理Event Handler,即EventHandler的容器,用以注册、移除EventHandler等;另外,它还作为Reactor模式的入口调用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,当阻塞等待返回时,根据事件发生的Handle将其分发给对应的Event Handler处理,即回调EventHandler中的handle_event()方法。

Proactor模式

Proactor主动器模式包含如下角色

  • Handle 句柄;用来标识socket连接或是打开文件;
  • Asynchronous Operation Processor:异步操作处理器;负责执行异步操作,一般由操作系统内核实现;
  • Asynchronous Operation:异步操作
  • Completion Event Queue:完成事件队列;异步操作完成的结果放到队列中等待后续使用
  • Proactor:主动器;为应用程序进程提供事件循环;从完成事件队列中取出异步操作的结果,分发调用相应的后续处理逻辑;
  • Completion Handler:完成事件接口;一般是由回调函数组成的接口;
  • Concrete Completion Handler:完成事件处理逻辑;实现接口定义特定的应用处理逻辑;

流程

    1. 应用程序启动,调用异步操作处理器提供的异步操作接口函数,调用之后应用程序和异步操作处理就独立运行;应用程序可以调用新的异步操作,而其它操作可以并发进行;
    1. 应用程序启动Proactor主动器,进行无限的事件循环,等待完成事件到来;
    1. 异步操作处理器执行异步操作,完成后将结果放入到完成事件队列;
    1. 主动器从完成事件队列中取出结果,分发到相应的完成事件回调函数处理逻辑中;

主动和被动

  • 以主动写为例: Reactor将handle放到select(),等待可写就绪,然后调用write()写入数据;写完处理后续逻辑; Proactor调用aoi_write后立刻返回,由内核负责写操作,写完后调用相应的回调函数处理后续逻辑; 可以看出,Reactor被动的等待指示事件的到来并做出反应;它有一个等待的过程,做什么都要先放入到监听事件集合中等待handler可用时再进行操作; Proactor直接调用异步读写操作,调用完后立刻返回;