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模拟登录百度代码分享(获取百度贴吧等级)
Dec 27 Python
关于django 数据库迁移(migrate)应该知道的一些事
May 27 Python
python 字典 按key值大小 倒序取值的实例
Jul 06 Python
Django中使用Celery的教程详解
Aug 24 Python
Python3 安装PyQt5及exe打包图文教程
Jan 08 Python
基于Python实现迪杰斯特拉和弗洛伊德算法
May 27 Python
Python实现的删除重复文件或图片功能示例【去重】
Apr 23 Python
Python中私有属性的定义方式
Mar 05 Python
python在地图上画比例的实例详解
Nov 13 Python
Python数据分析入门之教你怎么搭建环境
May 13 Python
Python深度学习之实现卷积神经网络
Jun 05 Python
Python Pandas解析读写 CSV 文件
Apr 11 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 友好URL的实现(吐血推荐)
2008/10/04 PHP
PHP 分页原理分析,大家可以看看
2009/12/21 PHP
基于php常用正则表达式的整理汇总
2013/06/08 PHP
PHP 验证码不显示只有一个小红叉的解决方法
2013/09/30 PHP
浅谈php冒泡排序
2014/12/30 PHP
PHP利用imagick生成组合缩略图
2016/02/19 PHP
PHP对象克隆clone用法示例
2016/09/28 PHP
Laravel使用memcached缓存对文章增删改查进行优化的方法
2016/10/08 PHP
详解在YII2框架中使用UEditor编辑器发布文章
2018/11/02 PHP
Firefox getBoxObjectFor getBoundingClientRect联系
2008/10/26 Javascript
Mootools 1.2教程 设置和获取样式表属性
2009/09/15 Javascript
获取网站跟路径的javascript代码(站点及虚拟目录)
2009/10/20 Javascript
JavaScript 对Cookie 操作的封装小结
2009/12/31 Javascript
HTML node相关的一些资料整理
2010/01/01 Javascript
有关JavaScript的10个怪癖和秘密分享
2011/08/28 Javascript
鼠标滑过出现预览的大图提示效果
2014/02/26 Javascript
深入理解JavaScript系列(44):设计模式之桥接模式详解
2015/03/04 Javascript
AngularJS基础学习笔记之简单介绍
2015/05/10 Javascript
实用又漂亮的BootstrapValidator表单验证插件
2016/05/30 Javascript
Js遍历键值对形式对象或Map形式的方法
2016/08/08 Javascript
jquery的checkbox,radio,select等方法小结
2016/08/30 Javascript
angular分页指令操作
2017/01/09 Javascript
vue-router3.0版本中 router.push 不能刷新页面的问题
2018/05/10 Javascript
node 文件上传接口的转发的实现
2019/09/23 Javascript
Python实现读写sqlite3数据库并将统计数据写入Excel的方法示例
2017/08/07 Python
Python 把序列转换为元组的函数tuple方法
2019/06/27 Python
如何通过python的fabric包完成代码上传部署
2019/07/29 Python
Python3实现发送邮件和发送短信验证码功能
2020/01/07 Python
贝佳斯官方网站:Borghese
2020/05/08 全球购物
Tea Collection官网:一家位于旧金山的童装公司
2020/08/07 全球购物
精彩的英文自荐信
2014/01/30 职场文书
整顿机关作风心得体会
2014/09/10 职场文书
不服从上级领导安排的检讨书
2014/09/14 职场文书
iPhone13再次曝光
2021/04/15 数码科技
Python如何把不同类型数据的json序列化
2021/04/30 Python
Python 中 Shutil 模块详情
2021/11/11 Python