Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. By using non-blocking network I/O, Tornado can scale to tens of thousands of open connections, making it ideal for long polling, WebSockets, and other applications that require a long-lived connection to each user.

non-blocking 非阻塞,显然还有一个 blocking;这实际上是一个操作系统非常底层的概念。一般来说操作系统提供接口或者原语,也可以叫做API能够完成阻塞或者非阻塞I/O。应用程序向操作系统发出请求、操作系统执行I/O处理,在开始执行I/O处理之前或者等待I/O处理完成再返回结果给应用程序。如果从发出请求到结果返回,一直阻塞,那就是阻塞I/O;如果发出请求就可以返回(完全不等待处理的完成和结果),就是非阻塞I/O;如果发出请求就返回,处理结果返回是阻塞在select或者poll上的,则其只能称为I/O复用 (multiplexing)。

blockingio.jpg

上图是一个阻塞模型,应用进程(process)和操作系统核心(kernel)的运行过程。

nonblockingio.jpg

上图是一个典型的非阻塞模型,每次调用马上返回

iomultiplexing.jpg

上图是一个I/O复用模型,一般通过select系统调用完成

所以这里面的non-blocking实际上是一个相当底层的概念,直接用在一个对Web框架的解说上,着实让人很是迷惑。

在传统Unix中,select或者poll这样的系统调用能够进行I/O复用,但是必须要遍历所有关注的文件描述符,这样就会随着文件描述符的数量增加导致遍历的处理过程也增长,任何文件描述符对应的网络连接有事件的时候,其他所有的没有啥关系的文件描述符都要被遍历一遍。对于一般的网络应用没有太大的问题,循环遍历几个文件描述符算不了什么,但是对于及时通讯或者移动设备消息推送这类程序来说,动辄十万,百万连接,并且每次系统select返回都是因为极少的网络I/O对应的文件描述符有事件,这可是个大事了。每个有效的文件描述符,都导致其他N-1个文件描述符被无辜地遍历一遍。谁也不答应。

EPOLL应运而生,EPOLL这个操作系统接口、原语、API能够让应用程序只需返回有事件的文件描述符,这样对select或者poll进行了复用的增强,当然epoll还在诸如内核空间与用户空间的内存复制很多地方进行了O优化,总之epoll能够应付多数网络I/O都是空闲的情况,不会让应用程序做无用功,使即时通讯和移动消息推送这类同时在一台机器上维护成百万网络连接成为可能。

Tornado就是基于epoll的,Tornado的non-blocking也就由此而来。

Tornado其实是非常容易阻塞的

如果你曾经用过Tornado,你就知道Tornado是单线程的,任何耗时操作都能把它真正堵塞掉,让它无法接受更多的网络请求。这是怎么回事?跟它的non-blocking好矛盾呀。

答案就在前面,因为你想达到的非阻塞的服务状态并非其I/O编程模型中的non-blocking。此“非阻塞”非彼“non-blocking”,人家在讲Tornado如何在使用操作系统提供的I/O接口,你却要你的Web程序无阻塞,典型一个风、马、牛。

当然若要实现用户请求的非阻塞,这是需要在整个服务架构上处理。让每个网络请求处理都快速返回,不进行任何数据库操作,不进行任何文件系统操作,不进行任何耗时的计算操作,不要for循环。就是把请求队列起来待处理,把网络连接保持着,其它什么都不要做。

PPMessage重度使用Tornado,所有的网络服务都是基于Tornado的。其中用Tornado实现的MQTT服务器,是目前可以测试到的MQTT服务中,性能最优的。

本文由原创,转发请注明出处。

 - 开源在线客服系统,移动应用内消息SDK,网页聊天,客户服务,同事沟通,私有的微信,自建的钉钉

欢迎在上

参考文章: