IO多路复用?我所理解的IO模式

1:IO的过程

  当我们调用系统函数read时,一般会经历两个阶段:

  1:等待数据准备(waiting for the data be ready)

  2:将数组从内核拷贝到进程(从内核态到用户态)(copying the data from the kernel to the process)

  在"等待数据准备"这个状态,我们最常见到的就是网路请求,即内核等待网络中的数据到网口的缓冲区。在数据到网口的缓冲区后,才会发生第二阶段,将数据从内核态拷贝到用户进程(用户态)。

  所以我么常说各种IO模型就是对这两个状态的不同的描述

2:常用的IO模型有哪些

  IO模型大体分为两大类:同步IO和异步IO;同步IO又包含:阻塞IO,非阻塞IO,IO多路复用,信号驱动IO

  区别是什么呢?当我们调用系统函数read时

  阻塞IO(blocking IO): 在上述的两个状态(等待数据和拷贝数据)都被阻塞了

  非阻塞IO(non-blocking IO):在这个场景中,在第一阶段,用户进程是会不断轮询kernel是否准备好数据。kernel准备没准备好数据都会返回,如果准备好,进行第二阶段。如果没准备好则返回error,用户进程收到error后会继续轮询知道数据准备好。

  IO多路复用(IO Multiplxing):又叫事件驱动IO。底层用的是 select/poll/epoll等调用,有点是单个线程可以监控多个网路IO。而在阻塞IO模型中,则必须使用多线程才能达到同样的效果。注意:这不意味着多路服用处理单个连接能处理的更快,只是单个线程能处理更多的连接。

  信号驱动(signal IO):这个场景中,用户进程会通知内核,在数据准备好后要发个信号通知用户进程;用户进程在收到信号后发起系统调用等待内核将数据拷贝到用户线程。在第二阶段仍是阻塞的。

  异步IO(asynchronous IO):这个和信号驱动类似,不同的是直到数据拷贝到用户进程后才会发信号通知用户进程。整个过程不会阻塞用户线程。 

3:IO多路复用和多线程的区别以及使用场景

  上面我们说到,在阻塞模式下,一个服务想要并行处理多个IO尽量使用多线程。但是创建线程耗时耗资源,所以我们一般都是使用线程池来代替多线程。

  我们也说到,多路复用可以单线程监控多个IO。而且单线程不会涉及到多线程同步的问题,也不会涉及到CPU线程上下文切换的问题。但是缺点也随之而来,如果同时有大量的IO需要处理的话,那么排在后面IO肯定等待的时间长。因此,这种场景适用于那些有大量连接,但是数据交互不频繁的场景,如聊天室。而多线程适用与那些大量短连接的场景,如web服务器。

  我们了解到的nginx,tornado,redis等都用了IO多路复用技术。Java中的NIO指的是(new IO),用的也是IO多路复用技术,而不是non-blocking IO。

4:计算密集型和IO密集型

  计算密集型任务最主要的是消耗CPU资源,即CPU运行时间/IO等待时间的比值高。如常见的加密解密,转码等操作都是很耗CPU的。在CPU密集型任务中,为了使CPU得到充分的利用,我们一般会采用多线程。但是线程数量不易太大,一般和CPU核心数持平,如果线程数量过大,可能会CPU会频繁的在线程间切换,造成资源浪费。而且CPU密集型任务使用执行效率比较高的语言也很重要。

  对于IO密集型任务,IO时间要远大于CPU运行时间。所以任务越多,那么CPU的效率也就越高。对于这种任务,使用执行效率高的语言对整体影响不大。我们可以在IO没有达到峰值的时候增加任务,如果IO已经达到峰值,再添加任务也只能等待了。

5:CPU和线程的关系

  CPU是系统资源,而线程可以看成我们的要执行指令的集合。我们的指令是否要执行是我们指定的,但是什么时候执行却是系统调度的。例如在线程执行一个阻塞命令时,CPU会闲置,也可以去处理其他的任务。

posted @ 2019-11-15 17:29  李斯特王  Views(719)  Comments(0Edit  收藏  举报