3. 传统IO数据拷贝、同步阻塞IO在哪里阻塞、同步阻塞IO怎么解决、IO多路复用、多路复用的特点、常见多路复用方案

3. 传统IO数据拷贝、同步阻塞IO在哪里阻塞、同步阻塞IO怎么解决、IO多路复用、多路复用的特点、常见多路复用方案

阅读顺序
1. CPU查找物理寻址和虚拟寻址、虚拟内存优点、不同位数的操作系统虚拟内存大小关系、Linux虚拟内存用户空间和内核空间
2. 进程切换、上下文及上下文切换、进程阻塞、文件描述符
3. 传统IO数据拷贝、同步阻塞IO在哪里阻塞、同步阻塞IO怎么解决、IO多路复用、多路复用的特点、常见多路复用方案

传统IO数据拷贝

请添加图片描述
比如一个Redis的读取操作,Redis的进程是在用户空间的,用户空间会通过系统调用去读取FD(文件描述符),通过系统调用比如通过 read/write去操作文件描述符 读取/写入数据,如果说这块文件的数据已经在用户空间缓存了,那就可以直接读到,如果数据是不存在的,那必须要先从磁盘硬件设备加载数据到内核的缓冲区里面,再从内核缓冲区复制数据到用户的缓冲区,那么在这个过程中,就发生了多次的数据拷贝,和上下文的切换

同步阻塞IO在哪里阻塞

请添加图片描述
当通过系统调用比如通过 read/write去操作文件描述符 读取/写入数据,但这个文件描述符当前是不可读的,那么系统不会直接给响应,也就是说,阻塞的地方是两个过程:

  • ①从磁盘硬件设备加载数据到内核的缓冲区里面这个过程是阻塞的
  • ②从内核缓冲区复制数据到用户的缓冲区这个过程也是阻塞的

直到从内核空间复制数据完毕,才会返回结果给到用户空间,然后阻塞的状态才会解除

同步阻塞IO怎么解决呢?

思路1:多线程处理阻塞的过程
在服务端(内核空间)使用线程池去创建多个线程来处理阻塞的两个过程
①从磁盘硬件设备加载数据到内核的缓冲区里面
②从内核缓冲区复制数据到用户的缓冲区

可以使用多线程,但不是一个很好的方案。
如果并发比较大,就会需要创建很多线程,导致线程数很大,可能造成系统不能够承受,而且线程数太多,创建线程和释放线程会比较消耗资源。

思路2:阻塞会造成用户空间傻等,让他不再傻等
用户空间不再傻等,而是轮询问内核空间有没有准备好,直到准备好之后返回数据,轮询的这种方式就叫做非阻塞IO了,因为不需要客户端(用户空间)一直等待。
这种方案,实时性不高,取决于轮询间隔,间隔大了,读取到的时间差就会很大,间隔太小,对于客户端(用户空间)也比较消耗性能。

所以服务端有没有更好的解决方案: 服务端就用一个线程,去处理多个客户端的请求呢?可以,IO多路复用 multiplexing。

IO多路复用 multiplexing

请添加图片描述
I/O: 指网络I/O
多路: 多个TCP连接(Socket或Channel,可以理解为多个客户端的连接)
复用: 复用服务端的一个或多个线程

设计思想是: 在服务端由内核去帮助应用程序去监视 FD(文件描述符) 是否就绪(数据有没有准备好),不再由客户端监视连接,由服务端去监视连接。

它是怎么做的呢?
在客户端操作的时候会有一个Socket,这个Socket是由事件类型的,服务端会有一个程序,IO多路复用器(或者叫IO多路复用程序)会将这些Socket的请求放入一个队列中,然后通过文件时间分派器转发到不同的事件处理器(如命令请求处理器、命令回复处理器等)。

多路复用是需要操作系统支持的,不同的操作系统有不同的实现。

多路复用的特点

请添加图片描述
通过一种机制,一个进程能同时等待多个 FD(文件描述符) ,而这些 FD(文件描述符) 其中的任意一个进入读就绪(readable)状态,select()函数就可以返回,不需要你去做轮询。

常见多路复用方案

  • evport是Solaris系统内核提供支持的
  • epoll是Linux系统内核提供支持的
  • kqueue是Mac系统内核提供支持的
  • select是POSIX提供的,一般的操作系统都有支撑(是一个保底方案,性能不如其它方案,基本上不会再使用)。

不同的多路复用的方案有各自的特点,epoll用的是最多的(以Redis的多路复用方案为例,源码ae.c定义epoll优先级最高,kqueue次之,保底是select)。

Redis多路复用
Redis源码:Redis源码怎么查看入门、Redis外部数据结构到Redis内部数据结构查看源码顺序、Redis源码查看顺序
Redis多路复用方案定义在ae.c文件
ae.c源码文件在解压后的src目录下
在这里插入图片描述

/* Include the best multiplexing layer supported by this system. 包含该系统支持的最佳多路复用层
 * The following should be ordered by performances, descending. 以下应按顺序依次递减*/
/*epoll优先级最高,kqueue次之,保底是select*/
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif

相关联

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值