2019独角兽企业重金招聘Python工程师标准>>>
2014年的时候我接触了 tornado (非阻塞式服务器), 里面有个概念叫做非阻塞。一开始我以为这个是某些 web 服务特有的,其实不是,这些功能应该要要依附于服务的操作系统(比如:Linux)。
问题一、 Linux 层面应该有如下一些 IO 模式
1. 阻塞I/O(blocking I/O)
2. 非阻塞I/O (nonblocking I/O)[ 轮训,这个轮训只轮训自己的通道] [连接数有优势] [拷贝数据阻塞]
3. I/O复用(select 和poll) (I/O multiplexing)[轮训,且轮训所有通道, 哪个好了,就给哪个返回, 比如select 可以同时处理多个阻塞I/O 操作][拷贝数据阻塞]
4. 信号驱动I/O (signal driven I/O (SIGIO))[不常用] [拷贝数据阻塞]
5. 异步I/O (asynchronous I/O (the POSIX aio_functions))[不需要轮训, 内核告诉用户已经完成了] [数据拷贝完成通知用户]
前四种都是同步,只有最后一种才是异步IO。为什么这么说呢?因为前面4种拷贝数据还需要请求一次,最后一种是拷贝数据完成了后通知用户进程。
问题二、 select, poll, epoll 的区别
select, poll, epoll 都是多路IO复用的解决方案;
select: 受限于 fd 查询标志位。每次轮训 socket 的个数为 fd 的size个数(不管当前socket 是否已经执行完成了,所以浪费性能,如果说可以把那些已经完成的socket做个标记,那么就可以不需要轮训所有的socket连接了)
poll : 本质和select 没什么区别,唯一区别是不受限于 fd 标记个数,使用链表来存储socket的连接状态,所以他能够保持 socket 连接数足够多。
epoll: 不是轮训机制,使用消息机制;
问题三、 fd (File Descriptor)标志位是什么
是内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符;
简单点说就是 linux 文件被打开(io)的个数;
但是Linux 系统会限制进程对文件打开的个数(比如是n),所以这个fd里面的值应该不超过n;
所以
其实在 Tornado 中所说的异步非阻塞其实和 linux中的关系不大;后来看了Torando 中的例子,其实就是一个回调操作,和Ajax的操作有点类似;
同步操作
from tornado.httpclient import HTTPClient def synchronous_fetch(url): http_client = HTTPClient() response = http_client.fetch(url) return response.body |
异步操作
from tornado.httpclient import AsyncHTTPClientdef asynchronous_fetch(url, callback): http_client = AsyncHTTPClient() def handle_response(response): callback(response.body) http_client.fetch(url, callback=handle_response) |
问题四、为什么Java web 中没有这种操作(异步处理请求)
其实是有的,现在大部分 java web 都是基于 servlet 的,在 servlet 3.0 开始就引入了异步机制。也是一个回调,使用异步,能够加大的同一台电脑对请求数处理的吞吐量。所以理论上来讲,异步操作比同步操作在单位时间内处理的请求应该更多。
[参考]:http://blog.csdn.net/historyasamirror/article/details/5778378(io 模型)
[参考]:https://segmentfault.com/a/1190000003063859 (io 模型)
[参考]:http://blog.csdn.net/jay900323/article/details/18141217 (io 模型)
[参考]:http://blog.csdn.net/cywosp/article/details/38965239(fd)
[参考]: https://zhangxh20.github.io/2017/07/03/asyncservlet/(servlet 异步处理请求)