tornado是一个很牛X的异步网络框架,内置了高性能的web服务器,可以很方便的写很多web服务
不过今天我要用它来实现非web类的网络应用

科普

首先,来了解下tornado的eventloop,在不同系统中,会用不同的方法,epoll(linux)和kqueue(BSD/MacOS),两者都不行的话退回到select模式。
顺便科普下,水平触发和边缘触发。python下默认就是LT模式,但是可以通过指定select.EPOLLET设置成ET模式。

1
2
3
epoll.register(connection.fileno(), select.EPOLLIN)
修改为
epoll.register(connection.fileno(), select.EPOLLIN|select.EPOLLET)

Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!

Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!

对比gevent

tornado: 单线程异步模型,没有线程之间切换的开销,整个处理流程非常高效。
gevent: 是基于协程(coroutine)实现的 Python 网络库,使用了轻量级的 greenlet 作为执行单元,并 基于 libevent 事件循环构建了直观的调用接口。

tornado实战

初始化ioloop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from tornado import ioloop
io_loop = ioloop.IOLoop.current()
# 或者下面的方式
io_loop = ioloop.IOLoop.instance()

# 为fd的改变增加处理方法,handler表示用什么处理,events表示发生了什么事
# events的取值:IOLoop.READ, IOLoop.WRITE, IOLoop.ERROR
io_loop.add_handler(fd, handler, events)
# 返回的时候会调用 handler(fd, events)
# 启动这个loop
io_loop.start()

# 当需要往外写的时候,转成IOLoop.WRITE
ioloop.update_handler(fd, IOLoop.WRITE)
# 当fd被关闭了,则从ioloop干掉这个
ioloop.remove_handler(fd)

database模块

从tornado3.0版本开始,框架不再提供database模块,改成torndb这个项目单独来运作。

项目地址:https://github.com/bdarnell/torndb