Python的Tornado框架异步编程入门实例


Posted in Python onApril 24, 2015

Tornado

Tornado 是一款非阻塞可扩展的使用Python编写的web服务器和Python Web框架, 可以使用Tornado编写Web程序并不依赖任何web服务器直接提供高效的web服务.所以Tornado不仅仅是一个web框架而且还是一款可以用于生产环境的高效的web服务器

Torando 在Linux和FreeBSD上使用高效的异步I/O模型 epoll 和kqueue来实现高效的web服务器, 所以 tornado在Linux上和FreeBSD系列性能可以达到最高
接口

当然我们可以不仅仅把Tornado看作是一个web框架和web服务器, 我们可以利用Tornado提供的接口进行高效的网络异步编程,

tornado.ioloop.IOLoop 提供了三个接口可以用于网络编程:

add_handler

def add_handler(self, fd, handler, events):
  self._handlers[fd] = stack_context.wrap(handler)
  self._impl.register(fd, events | self.ERROR)

add_handler用于添加socket到主循环中, 接受三个参数: fd 是socket的文件描述符 handler 是处理此socket的 callback函数 * events 是此socket注册的事件

update_handler

def update_handler(self, fd, events):
  self._impl.modify(fd, events | self.ERROR)

update_handler用于更新住循环中已存在的socket响应事件, 接受两个参数: fd 是socket对应的文件描述符 events 是注册的新事件

remove_handler

def remove_handler(self, fd):
  self._handlers.pop(fd, None)
  self._events.pop(fd, None)
  try:
    self._impl.unregister(fd)
  except Exception:
    gen_log.debug("Error deleting fd from IOLoop", exc_info=True)

remove_handler用于移除主循环中已存在的socket
事件

tornado.ioloop.IOLoop同时提供了4种响应事件:
Python的Tornado框架异步编程入门实例

实例

根据上面的接口和事件我们就可以写出一个简单的 echo server

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
#  Author :  cold
#  E-mail :  wh_linux@126.com
#  Date  :  13/04/15 15:08:51
#  Desc  :  Tornado Echo Server
#  HOME  :  http://www.linuxzen.com
#
import Queue
import socket

from functools import partial

from tornado.ioloop import IOLoop

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)       # 将socket设置为非阻塞

server_address = ("localhost", 10000)

sock.bind(server_address)
sock.listen(5)

fd_map = {}       # 文件描述符到socket的映射
message_queue_map = {}  # socket到消息队列的映射

fd = sock.fileno()
fd_map[fd] = sock

ioloop = IOLoop.instance()

def handle_client(cli_addr, fd, event):
  s = fd_map[fd]
  if event & IOLoop.READ:
    data = s.recv(1024)
    if data:
      print "   received '%s' from %s" % (data, cli_addr)
      # 接收到消息更改事件为写, 用于发送数据到对端
      ioloop.update_handler(fd, IOLoop.WRITE)
      message_queue_map[s].put(data)
    else:
      print "   closing %s" % cli_addr
      ioloop.remove_handler(fd)
      s.close()
      del message_queue_map[s]

  if event & IOLoop.WRITE:
    try:
      next_msg = message_queue_map[s].get_nowait()
    except Queue.Empty:
      print "%s queue empty" % cli_addr
      ioloop.update_handler(fd, IOLoop.READ)
    else:
      print 'sending "%s" to %s' % (next_msg, cli_addr)
      s.send(next_msg)

  if event & IOLoop.ERROR:
    print " exception on %s" % cli_addr
    ioloop.remove_handler(fd)
    s.close()
    del message_queue_map[s]


def handle_server(fd, event):
  s = fd_map[fd]
  if event & IOLoop.READ:
    conn, cli_addr = s.accept()
    print "   connection %s" % cli_addr[0]
    conn.setblocking(0)
    conn_fd = conn.fileno()
    fd_map[conn_fd] = conn
    handle = partial(handle_client, cli_addr[0])  # 将cli_addr作为第一个参数
    # 将连接和handle注册为读事件加入到 tornado ioloop
    ioloop.add_handler(conn_fd, handle, IOLoop.READ)
    message_queue_map[conn] = Queue.Queue()  # 创建对应的消息队列


ioloop.add_handler(fd, handle_server, IOLoop.READ)

ioloop.start()

上面代码就建立了一个非阻塞的高效的异步的echo server

Python 相关文章推荐
从零学Python之入门(四)运算
May 27 Python
python中List的sort方法指南
Sep 01 Python
python实现搜索本地文件信息写入文件的方法
Feb 22 Python
Python判断以什么结尾以什么开头的实例
Oct 27 Python
由面试题加深对Django的认识理解
Jul 19 Python
python logging模块书写日志以及日志分割详解
Jul 22 Python
python实现对图片进行旋转,放缩,裁剪的功能
Aug 07 Python
解决使用export_graphviz可视化树报错的问题
Aug 09 Python
如何基于Python实现数字类型转换
Feb 07 Python
Python新手学习装饰器
Jun 04 Python
Python sublime安装及配置过程详解
Jun 29 Python
Python内置函数及功能简介汇总
Oct 13 Python
使用Python的Tornado框架实现一个简单的WebQQ机器人
Apr 24 #Python
Python程序中使用SQLAlchemy时出现乱码的解决方案
Apr 24 #Python
简单说明Python中的装饰器的用法
Apr 24 #Python
使用基于Python的Tornado框架的HTTP客户端的教程
Apr 24 #Python
简单介绍Python的Tornado框架中的协程异步实现原理
Apr 23 #Python
解决Python中由于logging模块误用导致的内存泄露
Apr 23 #Python
粗略分析Python中的内存泄漏
Apr 23 #Python
You might like
利用curl 多线程 模拟 并发的详解
2013/06/14 PHP
php5.5新数组函数array_column使用
2013/07/08 PHP
smarty模板中拼接字符串的方法
2014/02/14 PHP
php curl上传、下载、https登陆实现代码
2017/07/23 PHP
利用ASP发送和接收XML数据的处理方法与代码
2007/11/13 Javascript
javascript不同页面传值的改进版
2008/09/30 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
2013/10/18 Javascript
javascript比较两个日期相差天数的方法
2015/07/24 Javascript
css如何让浮动元素水平居中
2015/08/07 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
2015/11/17 Javascript
JavaScript的ExtJS框架中数面板TreePanel的使用实例解析
2016/05/21 Javascript
Javascript中判断一个值是否为undefined的方法详解
2016/09/28 Javascript
BootStrap 图片样式、辅助类样式和CSS组件的实例详解
2017/01/20 Javascript
JavaScript提高加载和执行效率的方法
2017/02/03 Javascript
Bootstrap Table使用整理(一)
2017/06/09 Javascript
jQuery除指定区域外点击任何地方隐藏DIV功能
2017/11/13 jQuery
angularJs在多个控制器中共享服务数据的方法
2018/09/30 Javascript
详解JavaScript中的数据类型,以及检测数据类型的方法
2020/09/17 Javascript
js实现磁性吸附的示例
2020/10/26 Javascript
zbar解码二维码和条形码示例
2014/02/07 Python
在Python中使用lambda高效操作列表的教程
2015/04/24 Python
TensorFlow saver指定变量的存取
2018/03/10 Python
Python爬虫框架Scrapy基本用法入门教程
2018/07/26 Python
python模拟点击玩游戏的实例讲解
2020/11/26 Python
真正了解CSS3背景下的@font face规则
2017/05/04 HTML / CSS
美国网上订购鲜花:FTD
2016/09/23 全球购物
ALDI奥乐齐官方海外旗舰店:德国百年超市
2017/12/27 全球购物
RetroStage德国:复古服装
2019/02/03 全球购物
Weblogc domain问题
2014/01/27 面试题
用C语言实现文件读写操作
2013/10/27 面试题
违反交通法规检讨书
2014/09/10 职场文书
2014银行领导班子四风对照检查材料思想汇报
2014/09/25 职场文书
先进教师个人事迹材料
2014/12/15 职场文书
劳动保障个人工作总结
2015/03/04 职场文书
只需要100行Python代码就可以实现的贪吃蛇小游戏
2021/05/27 Python
css布局巧妙技巧之css三角示例的运用
2022/03/16 HTML / CSS