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的@property装饰器的用法
Apr 28 Python
连接Python程序与MySQL的教程
Apr 29 Python
python多线程方式执行多个bat代码
Jun 07 Python
完美解决Python2操作中文名文件乱码的问题
Jan 04 Python
在centos7中分布式部署pyspider
May 03 Python
Python数据类型之Set集合实例详解
May 07 Python
Django 开发调试工具 Django-debug-toolbar使用详解
Jul 23 Python
Python Django Cookie 简单用法解析
Aug 13 Python
wxPython实现文本框基础组件
Nov 18 Python
Java ExcutorService优雅关闭方式解析
May 30 Python
Python collections模块的使用方法
Oct 09 Python
python中的对数log函数表示及用法
Dec 09 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 水平的题目
2007/05/30 PHP
PHPExcel在linux环境下导出报500错误的解决方法
2017/01/26 PHP
Yii 框架入口脚本示例分析
2020/05/19 PHP
5款Javascript颜色选择器
2009/10/25 Javascript
Javascript的各种节点操作实例演示代码
2012/06/27 Javascript
javascript面向对象包装类Class封装类库剖析
2013/01/24 Javascript
jQuery+css实现图片滚动效果(附源码)
2013/03/18 Javascript
JS+CSS 制作的超级简单的下拉菜单附图
2013/11/22 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
原生js实现类似弹窗抖动效果
2015/04/02 Javascript
js基于cookie记录来宾姓名的方法
2016/07/19 Javascript
浅谈js-FCC算法Friendly Date Ranges(详解)
2017/04/10 Javascript
JavaScript 函数的定义-调用、注意事项
2017/04/16 Javascript
JavaScript 值类型和引用类型的初次研究(推荐)
2017/07/19 Javascript
Vue插件打包与发布的方法示例
2018/08/20 Javascript
弱类型语言javascript中 a,b 的运算实例小结
2019/08/07 Javascript
vue filter 完美时间日期格式的代码
2019/08/14 Javascript
JS面向对象编程基础篇(三) 继承操作实例详解
2020/03/03 Javascript
js实现点赞按钮功能的实例代码
2020/03/06 Javascript
vue结合el-upload实现腾讯云视频上传功能
2020/07/01 Javascript
实例讲解React 组件生命周期
2020/07/08 Javascript
通过实例了解Nodejs模块系统及require机制
2020/07/16 NodeJs
eslint+prettier统一代码风格的实现方法
2020/07/22 Javascript
js实现日历
2020/11/07 Javascript
Javascript实现单选框效果
2020/12/09 Javascript
基于JavaScript实现轮播图效果
2021/01/02 Javascript
Python3实现连接SQLite数据库的方法
2014/08/23 Python
Python+OpenCV让电脑帮你玩微信跳一跳
2018/01/04 Python
python实现拓扑排序的基本教程
2018/03/11 Python
用python简单实现mysql数据同步到ElasticSearch的教程
2018/05/30 Python
使用python实现快速搭建简易的FTP服务器
2018/09/12 Python
Django框架之DRF 基于mixins来封装的视图详解
2019/07/23 Python
员工保密协议书
2014/09/27 职场文书
前台岗位职责范本
2015/04/16 职场文书
redis哨兵常用命令和监控示例详解
2021/05/27 Redis
Element实现动态表格的示例代码
2021/08/02 Javascript