编程模式的变化
我们写服务器处理模型的程序时,有以下几种模型
(1)每收到一个请求,创建一个新的进程,来处理该请求;
(2)每收到一个请求,创建一个新的线程,来处理该请求;
(3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求
第(1)种现在肯定是不用了,没有人会傻到每次新来一个任务就会创建一个进程。
第(2)是比较常用的一种方式,但是一般大家都会想到一个问题,请求过多但是并不会无限制的创建线程,理论上也不可能一直创建线程,于是大家会采用线程池来处理。这是目前最常用的方式。但是创建线程池一定是完美的吗?当然不是,“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务,这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。但是,“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。
第(3)中就是事件驱动模型,流程如下
- 有一个事件(消息)队列
- 鼠标按下时,往这个队列中增加一个点击事件(消息);
- 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
- 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;
事件模型优点
1、支持重用,容易并发处理;2、有良好的扩展性;3、只需要单进程单线程处理所有请求这一块,减少资源的消耗
IO多路复用
在同一个线程里面, 通过快速拨开关的方式,来同时传输多个I/O流,ngnix(采用epoll模型)会有很多链接进来, epoll(包含事件驱动机制)会把他们都监视起来,然后监控他们的状态(事件驱动机制),当谁的状态发生变化时,也就是事件驱动机制监控到状态的变化,然后像拨开关一样,谁有状态就拨向谁,然后调用相应的代码处理。
出现的历史背景
select、poll、epoll
select、poll、epoll都是io多路复用的机制,区别如下
共同点就是大家都是io多路复用,不同点就是epoll采用事件驱动的方式。使得连接没有上限。