IO多路复用技术(multiplexing)

1、举例说明html

  假设你是一个老师,让30个学生解答一道题目,而后检查学生作的是否正确,你有下面几个选择:react

1. 第一种选择: 按顺序逐个检查,先检查A,而后是B,以后是C、D。。。这中间若是有一个学生卡主,全班都会被耽误。
这种模式就比如,你用循环挨个处理socket,根本不具备并发能力。
2. 第二种选择:你 建立30个分身,每一个分身检查一个学生的答案是否正确。 这种相似于为每个用户建立一个进程或者线程处理链接。
3. 第三种选择,你 站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,而后继续回到讲台上等。此时E、A又举手,而后去处理E和A。。。
这种就是IO复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,而后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操做。此时的socket应该采用 非阻塞模式
这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是 事件驱动,所谓的reactor模式。
(做者:郭春阳
连接:https://www.zhihu.com/question/28594409/answer/52835876
来源:知乎)
2、技术说明

技术上的问题,是将IO操做中等待和非等待的部分分开处理。咱们都知道IO操做分为两个部分:
一、等待数据就绪
二、处理数据多线程

 

众所周知的几种IO模型(阻塞、非阻塞、多路复用、信号驱动、异步)就是区别于这两个阶段,当须要处理不少链接的时候(高并发的状况),容易想到的是使用多线程技术,好比最简单的One-connection-Per-thread模式,可是由于等待数据不可避免,形成的结果是线程不停的休眠-唤醒的切换,致使CPU不堪重负。并发

IO复用的目的:将这两个阶段分开处理,让一个线程(并且是内核级别的线程)来处理全部的等待,一旦有相应的IO事件发生就通知继续完成IO操做,虽然仍然有阻塞和等待,可是等待老是发生在一个线程,这时使用多线程能够保证其余线程一旦唤醒就是处理数据,固然这须要非阻塞IO API的支持(好比非阻塞套接字)。Linux2.6以前的select,poll以及以后的epoll都是IO复用技术的实现。selectpoll基本一致,epoll是对它们的改进版本。但总的来讲它们都还不是真正的异步IO,由于它们在IO读写的时候仍然是阻塞的、同步的(完成一件过后才能作另一件事)。异步IO是指“处理数据”这一阶段也是非阻塞的。Windows上的IOCP(完成端口)才是真正的AIO,理论上它比Linux的epoll更先进。框架

至于select、poll和epoll的区别,推荐这篇文章:http://www.cnblogs.com/Anker/p/3265058.html。简单来讲:select,poll无脑的轮询,忽略了高并发下,轮询自己成了瓶颈,而epoll使用回调实现了轮询真正须要处理的链接。异步

 

Reactor模式是为了咱们更简单的使用IO复用技术。它是一种并发IO模式,其余的模式还有多进程,多线程等。Reactor自己也有不少变种,好比thread per request,worker thread,thread pool,multiple reactors...网上这方面的资料不少。虽然网上关于reactor和多线程模孰优孰劣还有争论(Reactor最明显的一个缺点是没法充分利用多核的优点),可是大部分高并发的框架或组建都是基于reactor的,好比MINA,Netty,再好比Redis,Nginx(有多个工做进程来充分利用多核的优点)。关于Java中的IO复用能够看Doug Lea大神的Scalable IO in Java(http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf)。socket