其实,区分清楚IO多路复用和异步AIO(Async IO)这两个概念就行了,架在多路复用上的非阻塞IO(同步IO),只是用起来像异步,从使用角度来看就是***通知机制,但本质上多路复用属于同步调用,同步在等待IO***这个操作上,例如 select epoll_wait等。AIO异步IO,可一次提交批量的IO操作。使用aio_xxx系列API,可通过信号或用户空间回调使用IO完成的数据。
题主详细描述的“IO复用属于同步IO”大致上是没问题的。
你的迷惑关键在于没有注意到部分与整体的关系。
首先统一下对同步和异步的看法:同步/异步是协作机制,如果是和线程相关时,线程阻塞(sleep)或者空转(轮询)时可以看成是该线程在同步等待***发生。
对于服务器网络模块设计来说,I/O多路复用必定会有一个轮询线程,这个线程可以看成同步的,它负责了全部的通信数据(请求)的接收。然后一般都是利用线程池的线程开始异步解析应用层协议消息,并进行请求的服务处理(当然考虑请求的性质,可能还会继续在服务内部进行并行处理)。所以从整体请求处理的角度看,是异步的。
所以,你可以说IO复用是同步的,twisted是异步的。
I/O多路复用
与I/O多路复用(I/O multiplexing)对应的是PPC和TPC模型,这里不展开。
I/O多路复用目前有几种模型:select,poll ,pselect,epoll。简要说下。
select:调用select(),调用线程一直循环阻塞等待消息,调用线程是同步的。
pselect:相比select提供了更精准的超时时间而已,调用线程是同步的。
poll :poll本质上和select没有区别,只是描述fd***的方式不同,poll使用pollfd结构而不是select的fd_set结构,调用线程是同步的。
epoll:同样需要一个线程在无限循环中调用epoll_wait等待注册的***,调用线程是同步的。
他们之间的最大的区别,是文件描述符数量限制,文件描述符遍历、***反馈机制方面的导致的cpu和内存***消耗等方面。所以linux的epoll和windows的完成端口都是高并发大量连接的服务器必须考虑的,也催生了libevent和libuv之类优秀的跨平台异步IO(这里的异步就是从并发请求处理来看的)库的产生。这里就不多说了,有很多详细的文章可看。
调用 OS API 都是同步的,不过你可以向OS注册一些你感兴趣的***,OS会将***关联到你注册的句柄上。然后你就需要同步的查询此句柄是否有你的***,有的话就去处理。这个处理过程你可以在同一个线程里处理,也可以放到一个队列里,让别的线程处理,这样就异步了。OS 给你提供基本的作料,如何炒菜还是靠你如何构架你的处理框架。
IO多路复用是同步还是异步看你站在哪个角度看的,IO多路复用比较经典的模型有selector,poll,epoll!
IO多路复用的发展背景:一开始C/S的通信,通常是Client端发起一个请求,然后Server端起一个对应的线程(或者进程)来处理,各个请求之间并不影响,随着用户越来越多,并发量越来越大,server端创建的线程逐渐的把整个计算机内存全部占用,导致服务器卡死!
这个时候IO多路复用开始成为主流,因为其理念为使用一个线程不断轮询的监听所有的连接,把活跃连接放入一个处理队列(selector和epoll有所不同),使用任务线程进行处理,这个时候所有的连接线程使用一个线程代替,并发量提高了很多,例如基于使用epoll模型的nginx,并发量几万的时候占用的线程也不过才几M!
回到题目本身,服务器在监听***的过程中,如果一直没有请求,那么监听的线程就是处于阻塞的,因为是使用的单线程监听,也没有异步的可能,但是在监听到***放入队列之后,起多个线程分别去处理这个连接,这肯定又是异步的,所以IO多路复用严格上来说是同步监听,异步处理的!
当然,IO多路复用并不是适用于所有的连接方式(长连接和短连接),如果是短连接,并且活跃***比较多的情况下,使用IO多路复用,监听线程会崩溃的,而改为使用基于线程池的多线程连接方式性能更好,如果是长连接的话,IO多路复用才能体现出极大的性能提升。
总的来说,IO多路复用在实际的开发中,用到的场景还是很多的,比如游戏开发,社交软件等,也是很多对服务器要求很高的公司招聘时着重强调的,掌握netty框架还是很有必要的,源码在github上有,可以下载来玩玩,更多的技术分享,敬请关注。。。
[免责声明]本文来源于网络,不代表本站立场,如转载内容涉及版权等问题,请联系邮箱:83115484@qq.com,我们会予以删除相关文章,保证您的权利。转载请注明出处:http://www.wito.com.cn/post/1649.html