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实现堆栈与队列的方法
Jan 15 Python
Python中的map()函数和reduce()函数的用法
Apr 27 Python
Python实现包含min函数的栈
Apr 29 Python
利用信号如何监控Django模型对象字段值的变化详解
Nov 27 Python
Python抽象和自定义类定义与用法示例
Aug 23 Python
在Python中增加和插入元素的示例
Nov 01 Python
用Python批量把文件复制到另一个文件夹的实现方法
Aug 16 Python
python2和python3应该学哪个(python3.6与python3.7的选择)
Oct 01 Python
pytorch下大型数据集(大型图片)的导入方式
Jan 08 Python
3种适用于Python的疯狂秘密武器及原因解析
Apr 29 Python
Python中的datetime包与time包包和模块详情
Feb 28 Python
Python实现归一化算法详情
Mar 18 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
模拟OICQ的实现思路和核心程序(一)
2006/10/09 PHP
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
PHP中比较时间大小实例
2014/08/21 PHP
Laravel框架Blade模板简介及模板继承用法分析
2019/12/03 PHP
iframe子页面与父页面在同域或不同域下的js通信
2014/05/07 Javascript
JavaScript中的this关键字使用方法总结
2015/03/13 Javascript
javascript学习笔记_浅谈基础语法,类型,变量
2016/09/19 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
Jil,高效的json序列化和反序列化库
2017/02/15 Javascript
Bootstrap进度条与AJAX后端数据传递结合使用实例详解
2017/04/23 Javascript
从setTimeout看js函数执行过程
2017/12/19 Javascript
js中Object.defineProperty()方法的不详解
2018/07/09 Javascript
webpack优化的深入理解
2018/12/10 Javascript
小程序日历控件使用方法详解
2018/12/29 Javascript
vue实现商品列表的添加删除实例讲解
2020/05/14 Javascript
[01:09:20]NB vs NAVI Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
[56:20]LGD vs VP Supermajor 败者组决赛 BO3 第三场 6.10
2018/07/04 DOTA
Python中实现结构相似的函数调用方法
2015/03/10 Python
Python中动态检测编码chardet的使用教程
2017/07/06 Python
python 连接各类主流数据库的实例代码
2018/01/30 Python
Python3.4实现远程控制电脑开关机
2018/02/22 Python
Pyqt实现无边框窗口拖动以及窗口大小改变
2018/04/19 Python
PyTorch线性回归和逻辑回归实战示例
2018/05/22 Python
Python3 执行Linux Bash命令的方法
2019/07/12 Python
关于pymysql模块的使用以及代码详解
2019/09/01 Python
浅谈基于HTML5的在线视频播放方案
2016/02/18 HTML / CSS
Christys’ Hats官网:英国帽子制造商
2018/11/28 全球购物
承诺书怎么写
2014/03/26 职场文书
英语故事演讲稿
2014/04/29 职场文书
2014年庆祝国庆65周年演讲稿
2014/09/21 职场文书
党的群众路线教育实践活动心得体会(教师)
2014/10/31 职场文书
2014年大学生工作总结
2014/11/20 职场文书
2015年教师学期工作总结
2015/04/30 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书
ubuntu安装jupyter并设置远程访问的实现
2022/03/31 Python
python垃圾回收机制原理分析
2022/04/13 Python