可以做展示页面的网站,上海高端网站建设,wordpress机械免费主题,如何安装wordpress操作系统 IO 相关知识 阻塞与非阻塞同步与异步IO 和系统调用传统的 IODMAmmap 内存映射sendfilesplice 常用的 IO 模型BIO#xff1a;同步阻塞 IONIO#xff1a;同步非阻塞 IOIO 多路复用信号驱动 IOAIO#xff1a;异步 IO 模型 IO 就是计算机内部与外部进行数据传输的过程同步阻塞 IONIO同步非阻塞 IOIO 多路复用信号驱动 IOAIO异步 IO 模型 IO 就是计算机内部与外部进行数据传输的过程比如网络 IO 与磁盘 IO 所有 IO 都需要系统调用由操作系统代理执行并经历从 IO 设备拷贝到内核空间拷到用户空间的环节
在内核收到调用请求之后会有数据准备、数据就绪、数据拷贝的阶段
每一个程序员面试的时候或多或少都会被问到相关知识了解一下相关概念是非常重要的
阻塞与非阻塞
阻塞与非阻塞指线程在等待调用结果数据消息返回值时的状态
阻塞是指应用线程等待结果时会被挂起等待内核或者 IO完成操作实际上内核所做的事情是将 CPU 时间切换给其他有需要的线程网络应用程序在这种情况下是得不到 CPU 时间做该做的事情的它会在那里睡觉。因此这里的阻塞应当理解成线程被其他线程阻塞或者等待 IO 资源结果的时候阻塞
非阻塞是指该线程等待结果数据准备时可以执行其他操作只有在拷贝数据的时候才会阻塞。此时该线程可以做一些其他的 CPU 计算但是一般会伴随不停的访问请求结果这一操作
注意阻塞与非阻塞的概念只有同步中才有没有异步阻塞与异步非阻塞的说法接下来说一下为什么
同步与异步
同步和异步关注的是消息通信机制
同步指发出调用请求后请求跟随调用结果一起返回
异步指发出请求后请求或者调用立即返回在 IO 设备或者其他的机器操作完毕后通过回调函数或者其他方式返回状态或者数据信息
比如我们使用消息队列来处理某个功能一般来说发生消息后就不用管之后的操作了该过程就是异步的。主线程不关心另一个线程怎么样所以谈不上阻塞非阻塞
IO 和系统调用
所有的 IO 操作都会有系统调用的过程同时所有的系统 IO 都分为两个阶段等待就绪和操作。举例来说读函数分为等待系统可读和真正的读同理写函数分为等待网卡可以写和真正的写
read(file, tmp_buf, len);
write(socket, tmp_buf, len);需要说明的是等待就绪的阻塞是不使用 CPU 的是在空等这期间数据通过网线以电流的方式输入我们的电脑并且被保存在缓冲区中而真正的读写操作的阻塞是使用 CPU 的即 CPU 将数据从缓冲区拷贝到目标位置的过程这个时候 CPU 真正在干活
传统的 IO
这里使用普通的 read 和 write 命令来展示一下传统 IO 的弊端
用户进程通过 read 方法向操作系统发起调用此时上下文从用户态转向内核态DMA 控制器把数据从硬盘或者套接字的缓冲区中拷贝到内核读缓冲区CPU 把内核读缓冲区数据拷贝到应用缓冲区然后上下文从内核态转为用户态read 和数据一起返回
其过程如下图所示
write 指令
用户进程通过 write 方法发起调用上下文从用户态转为内核态CPU 将应用缓冲区中数据拷贝到 socket 缓冲区DMA 控制器把数据从 socket 缓冲区拷贝到网卡上下文从内核态切换回用户态write 返回
read 和 write 分别进行了两次内核态用户态切换和两次 CPU 复制操作在操作系统中这些是可以被优化的
但是优化之前先处理一个问题我们可以看到数据会先复制到中间的 socket buffer 中我们很可能有一个问题就是为什么数据不能从磁盘直接复制到用户缓冲区原因主要在下面两点
1权限隔离操作系统的内核空间和用户空间是严格分离的以防止恶意程序直接访问系统资源造成系统不稳定或安全漏洞。内核负责管理硬件资源包括磁盘读写而用户空间的应用程序则运行在更高的抽象层次上 2地址空间不同内核空间和用户空间拥有各自的虚拟地址空间。用户缓冲区位于用户空间的虚拟地址范围内而内核在执行I/O操作时使用的是内核缓冲区这些缓冲区位于内核空间的地址范围内
DMA
DMA 是 Direct Memory Access直接内存存取
DMA 是直接内存访问技术他是一块主板上独立的芯片它专门用来进行内存和 IO 设备的数据传输他的主要作用是优化数据从磁盘拷贝到缓冲区这一过程 早期计算机中用户进程需要读取磁盘数据需要 CPU 中断和 CPU 参与就是整个数据的传输过程都要需要 CPU 亲自参与搬运数据的过程数据会先从磁盘拷贝到 CPU 寄存器然后再写入对应的缓冲区因此效率比较低发起 IO 请求每次的 IO 中断都带来 CPU 的上下文切换。 DMA 控制器接管了数据读写请求。并且加快了 IO 拷贝速度从而减少 CPU 的处理时间
mmap 内存映射
零拷贝技术是优化拷贝次数的技术以下的技术包括 mmap 都是零拷贝技术的一种
mmap 将用户空间的一段内存区域映射到内核空间映射成功后用户对这段内存区域的修改可以直接反映到内核空间同样内核空间对这段区域的修改也直接反映用户空间。即将用户空间和内核空间关联起来例如堆外内存就是 mmap 零拷贝技术
内核缓冲区和应用缓冲区共享从而减少了从内核缓冲区到用户缓冲区的一次 CPU 拷贝
sendfile
sendfile 方法 IO 数据对用户空间完全不可见所以只能适用于完全不需要用户空间处理的情况比如将磁盘中的数据复制到网卡
整个过程发生了两次用户态和内核态的上下文切换和三次拷贝数据不经过用户区只在内核态进行复制。简单介绍一下流程就是数据存在于内核中时并未被真正复制到 socket 关联的缓冲区内。取而代之的是只有记录数据位置和长度的描述符被加入到 socket 缓冲区中。DMA 模块将数据直接从内核缓冲区传递给协议引擎从而消除了遗留的最后一次复制
Linux2.4内核版本之后对 sendfile 做了进一步优化通过引入新的硬件支持这个方式叫做 DMA Scatter/Gather 分散/收集功能将整个过程优化到两次用户态和内核态的上下文切换和两次拷贝
splice
Linux 从2.6.17支持 splice 数据从磁盘读取到 OS 内核缓冲区后在内核缓冲区直接可将其转成内核空间其他数据 buffer而不需要拷贝到用户空间这是不是和 sendfile 有点像
注意 splice 和 sendfile 的不同sendfile 是 DMA 硬件设备不支持的情况下将磁盘数据加载到 kernel buffer内核空间维护的缓存空间后需要一次 CPU copy拷贝到 socket buffer
而 splice 是直接将两个内核空间的 buffer 进行 pipe 管道传输
#include fcntl.h
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);常用的 IO 模型 BIO同步阻塞 IO
同步阻塞 IO 模型该模型用于描述一方发起调用后阻塞等待另外一方返回的场景举几个例子
应用程序发起 read 调用后会一直阻塞直到在内核把数据拷贝到用户空间用户请求服务器后一直等待接口返回长连接
NIO同步非阻塞 IO
同步非阻塞 IO 模型中该模型用于描述一方发起调用后虽然等待该请求的结果但是我们依然执行自己的一些逻辑流程然后通过什么回调通知或者定时轮训来获取最终结果
在普通的 NIO 中应用程序会一直轮询发起 read 调用发起调用会降低 CPU 性能在数据准备的时间中线程不挂起直到磁盘准备好数据
数据就绪后实际的 IO 操作会等待数据复制到应用进程的缓冲区中以后才返回
IO 多路复用
java 中的 NIO、Radis 中的单线程、nginx 中的主进程就是 IO 多路复用使用选择器缓冲区、通道来实现通道将用户数据拷贝到缓冲区中选择器让程序读取缓冲区中数据IO 多路复用是 NIO 的一种但是它的好处是可以在同一条阻塞线程上处理多个不同端口的监听
多路 IO 共用一个同步阻塞接口任意 IO 可操作都可激活 IO 操作这是对阻塞 IO 的改进。此时阻塞发生在 select/poll 的系统调用上而不是阻塞在实际的 I/O 系统调用上。IO 多路复用的高级之处在于它能同时等待多个文件描述符而这些文件描述符套接字描述符其中的任意一个进入读就绪状态select 等函数就可以返回
信号驱动 IO
这是同步 IO 的一种。信号驱动 I/O 与异步 I/O 的区别是从缓冲区获取数据这个步骤的处理前者收到的通知是可以开始进行复制操作了在复制完成之前线程处于阻塞状态所以它仍属于同步 I/O 操作而后者收到的通知是复制操作已经完成
AIO异步 IO 模型
异步 IO 是基于事件或者回调机制实现的也就是应用操作之后会直接返回发送 read 直接得到结果不会堵塞在那里。举个例子
用户下单时会立马得到下单结果但是要等待一段时间后才可以收到下单成功通知