1,最常见的IO模型就是 “阻塞IO”
A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候不做其他的事情,十分专心。只有鱼上钩的时,才结束掉等的动作,把鱼钓上来。
在内核将数据准备好之前,系统调用会一直等待所有的套接字,默认的是阻塞方式。 然后从内核讲数据拷贝到用户线程。
程序的read必须在write之后执行,当write阻塞住了,read就不能执行下去,一直处于等待状态。
当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,当线程无限制增大之后,系统性能将急剧
下降,并会出现线程堆栈溢出,创建新线程失败。
2,第二种就是“伪异步IO”
通过线程池或者消息队列实现1个或多个线程处理N个客户端连接的模型,由于它的底层通信机制仍然会用同步阻塞I/O,所以被称为“伪异步”。通过线程池可以灵活地调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。会阻塞,其中一个类型的接口响应过慢,会导致其他请求都超时。
3,NIO 非阻塞IO(noblocking I/O)
B也在河边钓鱼,但是B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中,B也在做其他的事情(一会看看书,一会读读报纸,一会又去看其他人的钓鱼等),但B在做这些事情的时候,每隔一个固定的时间检查鱼是否上钩。一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。
其实,B在检查鱼竿是否有鱼,是一个轮询的过程。
每次客户询问内核是否有数据准备好,即文件描述符缓冲区是否就绪。当有数据报准备好时,就进行拷贝数据报的操作。当没有数据报准备好时,也不阻塞程序,内核直接返回未准备就绪的信号,等待用户程序的下一个轮寻。
但是,轮寻对于CPU来说是较大的浪费,一般只有在特定的场景下才使用。
4.信号驱动IO(signal blocking I/O)
C也在河边钓鱼,但与A、B不同的是,C比较聪明,他给鱼竿上挂一个铃铛,当有鱼上钩的时候,这个铃铛就会被碰响,C就会将鱼钓上来。
5.异步IO(asynchronous I/O)
E也想钓鱼,但E有事情,于是他雇来了F,让F帮他等待鱼上钩,一旦有鱼上钩,F就打电话给E,E就会将鱼钓上去。
当应用程序调用aio_read时,内核一方面去取数据报内容返回,另一方面将程序控制权还给应用进程,应用进程继续处理其他事情,是一种非阻塞的状态。
可以看出,阻塞程度:阻塞IO>非阻塞IO>多路转接IO>信号驱动IO>异步IO,效率是由低到高的。