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使用pil生成缩略图的方法
Mar 26 Python
python如何重载模块实例解析
Jan 25 Python
python3学生名片管理v2.0版
Nov 29 Python
python开发准备工作之配置虚拟环境(非常重要)
Feb 11 Python
Python变量类型知识点总结
Feb 18 Python
python爬虫 爬取超清壁纸代码实例
Aug 16 Python
PyQt+socket实现远程操作服务器的方法示例
Aug 22 Python
Python任务自动化工具tox使用教程
Mar 17 Python
浅谈Django中的QueryDict元素为数组的坑
Mar 31 Python
基于python实现数组格式参数加密计算
Apr 21 Python
python中return不返回值的问题解析
Jul 22 Python
Pycharm连接远程服务器并远程调试的全过程
Jun 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
ThinkPHP表单数据智能写入create方法实例分析
2015/09/27 PHP
php短信接口代码
2016/05/13 PHP
PHP后台微信支付和支付宝支付开发
2017/04/28 PHP
javascript 当前日期加(天、周、月、年)
2009/08/09 Javascript
JavaScript子窗口ModalDialog中操作父窗口对像
2012/12/11 Javascript
innerText和textContent对比及使用介绍
2013/02/27 Javascript
javascript制作坦克大战全纪录(2)
2014/11/27 Javascript
JavaScript 对象深入学习总结(经典)
2015/09/29 Javascript
Javascript基于AJAX回调函数传递参数实例分析
2015/12/15 Javascript
微信小程序商城项目之侧栏分类效果(1)
2017/04/17 Javascript
vue.js自定义组件directives的实例代码
2018/11/09 Javascript
vue.js仿hover效果的实现方法示例
2019/01/28 Javascript
通过npm或yarn自动生成vue组件的方法示例
2019/02/12 Javascript
Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)
2019/04/17 Javascript
nodejs dgram模块广播+组播的实现示例
2019/11/04 NodeJs
[01:14]DOTA2亚洲邀请赛小组赛赛前花絮
2017/03/27 DOTA
[01:28]国服启动器接入蒸汽平台操作流程视频
2021/03/11 DOTA
python中管道用法入门实例
2015/06/04 Python
Python返回数组/List长度的实例
2018/06/23 Python
对python中不同模块(函数、类、变量)的调用详解
2019/07/16 Python
用sqlalchemy构建Django连接池的实例
2019/08/29 Python
利用Python产生加密表和解密表的实现方法
2019/10/15 Python
Python列表如何更新值
2020/05/27 Python
如何用python开发Zeroc Ice应用
2021/01/29 Python
python调用百度AI接口实现人流量统计
2021/02/03 Python
CSS3样式linear-gradient的使用实例
2017/01/16 HTML / CSS
纯HTML5+CSS3制作图片旋转
2016/01/12 HTML / CSS
萌新HTML5 入门指南(二)
2020/11/09 HTML / CSS
加拿大最大的箱包及旅游配件零售商:Bentley Leathers
2017/07/19 全球购物
阿联酋航空丹麦官方网站:Emirates DK
2019/08/25 全球购物
大学军训感想
2014/02/12 职场文书
2014矛盾纠纷排查调处工作总结
2014/12/09 职场文书
幼儿园大班教师个人总结
2015/02/05 职场文书
小学生2015教师节演讲稿
2015/03/19 职场文书
趣味运动会通讯稿
2015/07/18 职场文书
MySQL库表名大小写的选择
2021/06/05 MySQL