上一篇讲了阻塞式IO,在阻塞IO中,如果有大量的并发请求,势必要针对请求开启多线程,针对每一个请求开启一个线程,这样每一个线程的处理时间就会包含之前的T1+T2这两个等待数据的时间,白白浪费了服务器的线程资源。
服务器核心要做的事情是等数据到了我再做事情。服务器的线程处理时间里面只需要包含数据到了后续部分。这样最大限度的利用了珍贵的服务器线程资源,并且由于线程的处理时间中没有包含等待数据的时间,可以使得线程快速释放。
现实生活中的例子,餐厅,阻塞IO类似于每来一个客人我马上分配一个厨师,让厨师等着客人点餐,然后再去做饭,厨师的工作就是做饭,但是在这个例子中,他却把时间白白浪费到了等待客人点单上。
如果有新的客人来,这个时候还得再分一个厨师给他,如果高峰时候,客人太多,一个客人分配一个厨师,厨师就会不够用,但是很多厨师却不是在忙着做饭,而是在盯着客人等待菜单。厨师的利用率非常低。
IO多路复用的核心便是解决服务器线程包含数据等待的时间的问题。
引入一个观察者线程,专门去监听系统IO,如果发现有数据ready了,便分配一个线程去处理。
改良餐厅的模式,老板招聘一个服务员,让服务员看着客人,如果有客人点餐结束,他立刻把点好的单子通知厨师,让厨师进行做饭。比如在两个客人先后到达,第一个客人点餐很快,菜也很简单,厨师小张很快就做完了第一个客人的饭。这个时候第二个客人的餐也点完了,厨师小张可以继续为第二个客人做饭,很明显,效率极大提升。
多路是指多个IO输入,在本例中,是指多个客人。
复用的就是那个观察者线程,本例中就是那个服务员。
在linux中多路复用是通过epoll(类似于服务员)来实现的。epoll会监控已经连接的Socket(类似于客人),当socket对应的IO变为可读后(客人点完了菜),通知应用进程(类似于厨师)进行读取,应用进程把数据从内核复制到用户空间的过程,就类似于厨师。
epoll为什么能够快速的监控到IO就绪,组员专门来介绍,本文暂时不做说明。select,和poll是之前的实现,epoll是最新的实现,性能最好。
联系客服