Tornado 的 IOStream 简介与应用

标签: tornado iostream 简介 | 发表时间:2011-10-02 19:08 | 作者:(author unknown) Ken
出处:http://simple-is-better.com/

Tornado的核心源码是由ioloop.py和iostream.py这2个文件组成的。前者提供了一个循环,用于处理I/O事件;后者则封装了一个非阻塞的socket。
有了这2者后,就能搭建起TCP server和HTTP server,实现异步HTTP客户端,这便是Tornado的主要内容了。
之前在研究socket时已差不多弄懂了ioloop的逻辑,于是本文就接着研究iostream了。

这里我并不想逐行分析iostream的源码,因为并不是什么很难懂的代码,于是只说说它做了些什么事。
先看IOStream的__init__()方法,重要的参数只有socket和io_loop这2个。所以很容易猜想到,它只是封装了这个socket,然后把I/O事件注册到io_loop上。
读了源码就能很快证实我们的猜测,值得注意的是,封装socket时还将其设为非阻塞的了。
此后在连接和读写时都调用了_add_io_state()方法,这个方法就是调用io_loop的add_handler()和update_handler()方法来注册事件的。
此外,似乎没有开放读完所有数据的接口,要自行实现的话可以使用_read_to_buffer()方法。

看完源码可能还是一头雾水,它究竟能用来干啥呢?
最为重要的用处当然是实现TCPServer了。有了ioloop,一个服务器就可以处理I/O事件了;可是I/O并不能凭空产生啊,它还需要通过socket连接和传输。
而正如前面所说,IOStream封装了socket,把它变成了非阻塞的,每次连接和读写这些I/O事件都注册到io_loop上,这样就实现了一个完整的TCPServer了。
可惜Tornado源码里的TCPServer并没有实际功能,HTTPServer又太复杂了,所以我找了一段echo server的代码,一看就知道用了。测试也很简单,用telnet连上去后,输入什么就会回显什么。

另一个功能还是和非阻塞有关。
Tornado能够以单线程处理高并发,靠的就是非阻塞。而假如其中的任何一次I/O是非阻塞的,需要消耗数毫秒甚至数秒,那么每秒能处理的请求数就不可能超过1000了。
所以这些耗时很长I/O访问必须封装成非阻塞的,而这早就被IOStream做好了。

此外,为了提高服务的响应速度,也需要用到异步处理。
以前几天我写的聊天室为例,当用户发送了一条信息后,我需要把它广播给所有的用户,然后才能结束这次响应。
在这个例子中,用户可能不需要等待多久。可是假如我还需要做一些复杂的处理,比如关键字过滤,分析@用户名、URL,保存到数据库,或者发送email等,我并不想让用户的请求一直被阻塞着。
那么我可以搭建另一个TCPServer,将接收到的信息通过IOStream发送给它,然后立即结束响应。在那个TCPServer上,我想做任何耗时的事,都不会拖慢主HTTPServer的响应速度;而一旦完成处理,就可以将结果通过IOStream返回给HTTPServer,让其完成扫尾工作。

这里仍然以聊天室为例,当接收到信息后,我将其发送给EchoServer,并结束响应。
EchoServer返回输入的信息,此时HTTPServer监听到这个事件,就读取并广播信息。
虽然对用户来说,效果是一样的。不过整个系统的扩展性就增强了,你可以把这个EchoServer替换成消息队列、memcache等各种数据源。虽然实现上仍有很大差异,但最重要的思路是一致的。

代码和上次的聊天室差不多,handler部分都一样,我就只贴出更改的部分吧:

import logging
import os.path
import socket
import uuid
import tornado.httpserver
import tornado.ioloop
import tornado.iostream
import tornado.options
import tornado.web
import tornado.websocket


def broadcast_message(message):
for handler in ChatSocketHandler.socket_handlers:
  try:
   handler.write_message(message)
  except:
   logging.error('Error sending message', exc_info=True)

for callback in ChatHandler.callbacks:
  try:
   callback(message)
  except:
   logging.error('Error in callback', exc_info=True)
ChatHandler.callbacks = set()

def send_message(message):
stream.write((message + '\n').encode('utf-8'))

def read_message_from_echo_server():
def broadcast(message):
  broadcast_message(message[:-1])
  read_message_from_echo_server()
stream.read_until('\n', broadcast)

# ...

if __name__ == '__main__':
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
stream.connect(('127.0.0.1', 8888))
read_message_from_echo_server()

main()

 

要注意的是,连接EchoServer需要在调用ioloop的start()方法之前,因为这个方法是个死循环,后面的代码没机会执行。

# 来源:keakon的涂鸦馆


在微博上关注: 新浪, 腾讯   投稿

最新招聘

更多>>

相关 [tornado iostream 简介] 推荐:

Tornado 的 IOStream 简介与应用

- Ken - python.cn(jobs, news)
Tornado的核心源码是由ioloop.py和iostream.py这2个文件组成的. 前者提供了一个循环,用于处理I/O事件;后者则封装了一个非阻塞的socket. 有了这2者后,就能搭建起TCP server和HTTP server,实现异步HTTP客户端,这便是Tornado的主要内容了. 之前在研究socket时已差不多弄懂了ioloop的逻辑,于是本文就接着研究iostream了.

#Tornado# 文档翻译中文版

- sasiky - python.cn(jobs, news)
内容索引 Table of Contents. 4.1   请求处理和请求参数. 4.2   RequestHandler中的主要方法. 4.4   Cookies和安全Cookies. 4.6   跨站伪造请求的防范. 4.7   静态文件和主动式文件缓存. 4.10   非阻塞式的异步请求. 7   WSGI 和 Google AppEngine.

Torrent Tornado:浏览器内 BT 下载

- - LinuxTOY
Torrent Tornado 是一款完全使用 JavaScript 实现的附加组件,可以为 Firefox 浏览器增加 BT 下载功能. 体积小巧(不到 100K),完全使用 JavaScript 实现,跨平台且无本地二进制依赖. 支持和磁力链接及种子文件关联. 注意 当前 1.0 版本仅支持下载,不支持上传.

基于tornado的异步TCPServer以及TCPClient

- - ITeye博客
关于tornado,我这里就不详细讲了,有兴趣的同学可以通过以下两篇博客了解一下:. 我们一般用tornado来编写web程序,但实际上,tornado底层的代码非常优秀,也可以用这些代码来编写TCP应用. tornado最突出的特点就是“异步”,所以,我这里编写了一个异步的TCPServer和一个异步的TCPClient来帮助大家理解,下面直接看代码:.

C++ 工程实践(7):iostream 的用途与局限

- tangsty - 博客园-陈硕的 Blog
陈硕 (giantchen_AT_gmail). 陈硕关于 C++ 工程实践的系列文章: http://blog.csdn.net/Solstice/category/802325.aspx. 陈硕博客文章合集下载: http://blog.csdn.net/Solstice/archive/2011/02/24/6206154.aspx.

用 Tornado 实现简单的在线代理

- Ken - python.cn(jobs, news)
实现代理的方式很多种,流行的web服务器也大都要代理的功能,比如http://www.tornadoweb.cn用的就是nginx的代理功能做的tornadoweb官网的镜像. 最近,我在开发一个移动运用(以下简称APP)的后台程序(Server),该运用需要调用到另一平台产品(Platform)的API.

用Tornado打造WebSocket与Ajax Long-Polling自适应聊天室

- satan - keakon的涂鸦馆
这几天忙着研究Tornado,想着总得学以致用吧,于是就决定做个聊天室玩玩. 实际上在Tornado的源码里就有chat和websocket这2个聊天室的demo,分别采用Ajax Long-Polling和WebSocket技术构建. 而我要实现的则很简单:将这2种技术融合在一起. 就技术而言,WebSocket的通信开销很少,没有连接数的限制,但由于本身比较新,支持它的浏览器并不多(目前仅有Chrome 6+、Safari 5.0.1+、Firefox 4+和Opera 11+,且Firefox和Opera还因安全原因默认禁用了).

Flask, Tornado, GEvent, 以及它们的结合的性能比较

- Ken - python.cn(jobs, news)
英文: http://blog.wensheng.com/2011/10/performance-of-flask-tornado-gevent-and.html. 我在选一个python的互联网框架, 本来已经定下来用Tornado了.  但我还听到很多人推荐Flask的简单性和灵活性, 还有gevent的高性能, 所以决定也试试它们以及它们和Tornado的结合.

Browser和Server持续同步的几种方式(jQuery+tornado演示)

- mrluanma - 残阳似血的博客
在B/S模型的Web应用中,客户端常常需要保持和服务器的持续更新. 这种对及时性要求比较高的应用比如:股票价格的查询,实时的商品价格,自动更新的twitter timeline以及基于浏览器的聊天系统(如GTalk)等等. 由于近些年AJAX技术的兴起,也出现了多种实现方式. 本文将对这几种方式进行说明,并用jQuery+tornado进行演示,需要说明的是,如果对tornado不了解也没有任何问题,由于tornado的代码非常清晰且易懂,选择tornado是因为其是一个非阻塞的(Non-blocking IO)异步框架(本文使用2.0版本).