IO复用的历史和多进程一样长,Linux很早就提供了select
系统调用,可以在一个进程内维护1024个连接,后来加入poll
系统调用,poll
做了一系列改进后解决了1024个连接的限制问题,可以维持任意数量的连接。但是select
和poll
存在一个问题是,它们需要循环检测连接是否有事件。这样问题就来了,如果服务器有100w个连接,在某一时间只有一个连接是向服务器发送了数据,select/poll
就需要做100w次循环,而其中只会有1次命中,剩下99w9999次都是无效的,白白浪费CPU时间片资源。
直到Linux2.6(2003年12月发布)内核开始提供新的epoll
系统调用,可以维持无限数量的连接,而且无需轮询,这才真正解决了C10K问题。现在各种高并发异步IO的服务器程序都是基于epoll
实现的,如Nginx、Node.js、Erlang、Golnag。像Node.js这样单进程单线程的程序,都可以维持超过100wTCP连接,这全部都要归功于epoll
技术。
应为我们的80端口主进程最多只能生成1024个socket[socket其实就是连接],所以使用select模型,不管你生成多少子进程,再多的连接主进程都不能创建socket了,它只会把这1024 socket连接分配给子进程。
还有就是在select模型下,这些socket是在select调用前就有的,然后调用select监控socket,也就是select(socket),此时我们的进程是处于阻塞的,但是select一直在遍历,当发现某个socket有数据了,此时就通知进程,然后进程就发送系统调用,此时该进程就发送read系统调用来读数据。这个read也要遍历这些所有socket才能取得想要数据。
poll本质上和select没有区别,与select的区别的是他没有最大连接数的限制,原因是他是基于链表来存储的。如果它一个进程内维护100w个连接,那poll遍历也需要很多时间。然后它再通知进程有一个socket有消息了,那么这个进程也遍历100w个socket,此时也需要不少时间。
epoll和poll类似,不限制连接数,但是epoll模型不需要遍历,当某个socket有数据的时候,直接通知进程,然后进程直接去那个socket中取。这时进程也不用遍历了。
如果把上面的都理解为单进程单线程,那么其实就是这个线程处理上面的socket内容,每个socket其实就是一个请求,所以io复用能处理多请求
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)