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 11 Python
python批量提取word内信息
Aug 09 Python
Python 获取当前所在目录的方法详解
Aug 02 Python
python+pyqt实现右下角弹出框
Oct 26 Python
Python排序搜索基本算法之希尔排序实例分析
Dec 09 Python
使用Python AIML搭建聊天机器人的方法示例
Jul 09 Python
Python Dataframe 指定多列去重、求差集的方法
Jul 10 Python
浅谈Pycharm调用同级目录下的py脚本bug
Dec 03 Python
python将一个英文语句以单词为单位逆序排放的方法
Dec 20 Python
深入理解Tensorflow中的masking和padding
Feb 24 Python
python 写一个性能测试工具(一)
Oct 24 Python
Django实现翻页的示例代码
May 24 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
PHP下用rmdir实现删除目录的三种方法小结
2008/04/20 PHP
php+mysql事务rollback&commit示例
2010/02/08 PHP
五款常用mysql slow log分析工具的比较分析
2011/05/22 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
PHP变量赋值、代入给JavaScript中的变量
2015/06/29 PHP
PHP的Socket通信之UDP通信实例
2015/07/02 PHP
yii2.0实现验证用户名与邮箱功能
2015/12/22 PHP
js 格式化时间日期函数小结
2010/03/20 Javascript
javascript对select标签的控制(option选项/select)
2013/01/31 Javascript
javascript 弹出的窗口返回值给父窗口具体实现
2013/11/23 Javascript
php实例分享之实现显示网站运行时间
2014/05/20 Javascript
jquery实现勾选复选框触发事件给input赋值
2015/02/01 Javascript
jQuery基于正则表达式的表单验证功能示例
2017/01/21 Javascript
jQuery实现 上升、下降、删除、添加一行代码
2017/03/06 Javascript
jQuery实现的背景颜色渐变动画效果示例
2017/03/24 jQuery
Bootstrap模态框插件使用详解
2017/05/11 Javascript
详解Vue2.0 事件派发与接收
2017/09/05 Javascript
JavaScript设计模式之享元模式实例详解
2019/01/17 Javascript
js实现倒计时器自定义时间和暂停
2019/02/25 Javascript
浅谈express.js框架中间件(middleware)
2019/04/07 Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
2019/04/11 Javascript
JS实现返回上一页并刷新页面的方法分析
2019/07/16 Javascript
vue-socket.io接收不到数据问题的解决方法
2020/05/13 Javascript
python基于queue和threading实现多线程下载实例
2014/10/08 Python
python+selenium 定位到元素,无法点击的解决方法
2019/01/30 Python
用python建立两个Y轴的XY曲线图方法
2019/07/08 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
python匿名函数lambda原理及实例解析
2020/02/07 Python
matplotlib bar()实现多组数据并列柱状图通用简便创建方法
2021/02/24 Python
python实现学生通讯录管理系统
2021/02/25 Python
GafasWorld哥伦比亚:网上购买眼镜
2017/11/28 全球购物
递归计算如下递归函数的值(斐波拉契)
2012/02/04 面试题
英语演讲稿范文
2014/01/03 职场文书
农村婚礼主持词
2014/03/13 职场文书
公司副总经理任命书
2014/06/05 职场文书
2016年世界艾滋病日宣传活动总结
2016/04/01 职场文书