python tornado写tornado的web服务器器脚本,运行时每过一会儿都会发出如下警告,这是怎么回事儿? 该如何解决?

Python Web框架Tornado运行和部署
作者:zzir
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Python Web框架Tornado运行和部署的相关资料,需要的朋友可以参考下
本文实例为大家分享了Python Web框架Tornado运行和部署的详细内容,供大家参考,具体内容如下
一、运行和部署
因为Tornado内置了自己的HTTPServer,运行和部署它与其他Python web框架不太一样。你需要写一个main()函数来启动服务,而不是配置一个WSGI容器来运行你的应用:
def main():
app = make_app()
app.listen(8888)
IOLoop.current().start()
if __name__ == '__main__':
配置你的操作系统或者进程管理器来运行这个程序以启动服务。注意,增加每个进程允许打开的最大文件句柄数是可能是必要的(为了避免“Too many open files” 的错误)。为了增加这个上限(例如设置为50000 ) 你可以使用ulimit命令,修改/etc/security/limits.conf 或者设置minfds 在你的supervisord配置中。
二、进程和端口
由于Python的GIL(全局解释器锁),为了充分利用多CPU的机器,运行多个Python 进程是很有必要的。通常,最好是每个CPU运行一个进程。
Tornado包含了一个内置的多进程模式来一次启动多个进程,这需要一个在main 函数上做点微小的改变:
def main():
app = make_app()
server = tornado.httpserver.HTTPServer(app)
server.bind(8888)
server.start(0) # forks one process per cpu
IOLoop.current().start()
这是最简单的方式来启动多进程并让他们共享同样的端口,虽然它有一些局限性。首先,每个子进程将有它自己的IOLoop,所以fork之前,不接触全局 IOLoop 实例是重要的(甚至是间接的)。其次,在这个模型中,很难做到零停机 (zero-downtime)更新。最后,因为所有的进程共享相同的端口,想单独监控它们就更加困难了。
对更复杂的部署,建议启动独立的进程,并让它们各自监听不同的端口, supervisord 的“进程组(process groups)”功能是一个很好的方式。当每个进程使用不同的端口,一个外部的负载均衡器,例如HAProxy或nginx通常需要对外向访客提供一个单一的地址。
三、运行在负载均衡器后面
当运行在一个负载均衡器例如nginx,建议传递xheaders=True 给 HTTPServer 的构造器。这将告诉Tornado使用类似 X-Real-IP 这样的HTTP头来获取用户的IP地址而不是把所有流量都认为来自于负载均衡器的IP地址。
这是一份原始的nginx配置文件,在结构上类似于我们在FriendFeed所使用的配置。这是假设nginx和Tornado server运行在同一台机器上的,并且四个 Tornado server 正运行在8000 - 8003端口:
worker_processes 1;
error_log /var/log/nginx/error.
pid /var/run/nginx.
worker_connections 1024;
# Enumerate all the Tornado servers here
upstream frontends {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
include /etc/nginx/mime.
default_type application/octet-
access_log /var/log/nginx/access.
keepalive_timeout 65;
proxy_read_timeout 200;
gzip_min_length 1000;
gzip_types text/plain text/html text/css text/xml
application/x-javascript application/xml
application/atom+xml text/
# Only retry if there was a communication error, not a timeout
# on the Tornado server (to avoid propagating "queries of death"
# to all frontends)
proxy_next_
listen 80;
# Allow file uploads
client_max_body_size 50M;
location ^~ /static/ {
root /var/
if ($query_string) {
location = /favicon.ico {
rewrite (.*) /static/favicon.
location = /robots.txt {
rewrite (.*) /static/robots.
location / {
proxy_pass_header S
proxy_set_header Host $http_
proxy_set_header X-Real-IP $remote_
proxy_set_header X-Scheme $
proxy_pass http://
四、静态文件和文件缓存
Tornado中,你可以通过在应用程序中指定特殊的 static_path 来提供静态文件服务:
settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
"cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
"login_url": "/login",
"xsrf_cookies": True,
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
(r"/(apple-touch-icon\.png)", tornado.web.StaticFileHandler,
dict(path=settings['static_path'])),
], **settings)
这些设置将自动的把所有以 /static/ 开头的请求交由static目录,例如http://localhost:8888/static/foo.png 将会通过指定的static目录提供 foo.png 文件。我们也会自动从static目录提供 /robots.txt 和 /favicon.ico (尽管它们并没有以 /static/ 前缀开始)。
在上面的设置中,我们明确的配置Tornado从 StaticFileHandler 根下获取 apple-touch-icon.png 文件,虽然文件在static文件目录中。(正则表达式捕获组必须告诉 StaticFileHandler 请求的文件名,调用捕获组把文件名作为方法的参数传递给处理程序) 你可以做同样的事情,比如从网站的根提供 sitemap.xml 文件。 当然,你也可以通过在你的HTML中使用 &link /& 标签来避免伪造根目录的 apple-touch-icon.png 。
为了改善性能,通常情况下,让浏览器主动缓存静态资源是个好主意, 这样浏览器就不会发送不必要的可能在渲染页面时阻塞的 If-Modified-Since 或 Etag 请求了, Tornado使用 静态内容版本(static content versioning) 来支持此项功能。
为了使用这些功能,在你的模板中使用 static_url 方法,而不是直接在你的HTML中输入静态文件的URL:
&title&FriendFeed - {{ _("Home") }}&/title&
&div&&img src="{{ static_url("images/logo.png") }}"/&&/div&
static_url() 函数将把相对路径翻译成一个URI类似于 /static/images/logo.png?v=aae54.其中的 v 参数是 logo.png 内容的哈希(hash),并且它的存在使得Tornado服务向用户的浏览器发送缓存头,这将使浏览器无限期的缓存内容。
因为参数 v 是基于文件内容的,如果你更新一个文件并重启服务,它将发送一个新的 v 值,所以用户的浏览器将会自动的拉去新的文件。如果文件的内容没有改变,浏览器将会继续使用本地缓存的副本,而不会从服务器检查更新,显著的提高了渲染性能。
在生产中,你可能想提供静态文件通过一个更优的静态服务器, 比如nginx,你可以配置任何web服务器识别通过 static_url() 提供的版本标签并相应的设置缓存头。下面是我们在 FriendFeed 使用的nginx相关配置的一部分:
location /static/ {
root /var/friendfeed/
if ($query_string) {
五、Debug模式和自动重载
如果传递 debug=True 配置给 Application 的构造函数,应用程序将会运行在debug/开发模式。 在这个模式下,为了方便于开发的一些功能将被启用( 每一个也可以作为独立的标签使用,如果它们都被专门指定,那它们都将获得独立的优先级):
1、autoreload=True: 应用程序将会观察它的源文件是否改变,并且当任何文件改变的时候便重载它自己。这减少了在开发中需要手动重启服务的需求。然而,在debug模式下,某些错误(例如import的时候有语法错误)会导致服务 关闭,并且无法自动恢复。
2、compiled_template_cache=False: 模板将不会被缓存。
3、static_hash_cache=False: 静态文件哈希 (被 static_url 函数使用) 将不会被缓存。
4、serve_traceback=True: 当一个异常在 RequestHandler 中没有捕获,将会生成一个包含调用栈信息的错误页。
自动重载(autoreload)模式和 HTTPServer 的多进程模式不兼容,你不能给 HTTPServer.start 传递 1 以外的参数(或者调用 tornado.process.fork_processes) 当你使用自动重载模式的时候。
debug模式的自动重载功能可作为一个独立的模块位于 tornado.autoreload。以下两者可以结合使用,在语法错误之时提供额外的健壮性: 设置 autoreload=True 可以在app运行时检测文件修改,还有启动 python -m tornado.autoreload myserver.py 来捕获任意语法错误或者其他的启动时错误。
重载会丢失任何Python解释器命令行参数(-u). 因为它使用 sys.executable 和 sys.argv 重新执行Python。此外,修改这些变量将造成重载错误。
在一些平台(包括Windows 和Mac OSX 10.6之前),进程不能被“原地”更新,所以当检测到代码更新,旧服务就会退出然后启动一个新服务。这已经被公知来混淆一些IDE。
六、WSGI和Google App Engine
Tornado通常是独立运行的,不需要一个WSGI容器。然而,在一些环境中 (例如Google App Engine),只运行WSGI,应用程序不能独立运行自己的服务。在这种情况下,Tornado支持一个有限制的操作模式,不支持异步操作但允许一个Tornado's功能的子集在仅WSGI环境中。以下功能在WSGI模式下是不支持的,包括协程,@asynchronous 装饰器,AsyncHTTPClient,auth 模块和WebSockets。
你可以使用 tornado.wsgi.WSGIAdapter 把一个Tornado Application 转换成WSGI应用。在这个例子中, 配置你的WSGI容器发 现 application 对象:
import tornado.web
import tornado.wsgi
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
tornado_app = tornado.web.Application([
(r"/", MainHandler),
application = tornado.wsgi.WSGIAdapter(tornado_app)
以上就是本文的全部内容,希望对大家的学习有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具您所在位置: &
&nbsp&&nbsp
python tornado中文文档.doc 24页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
需要金币:50 &&
你可能关注的文档:
··········
··········
下载和安装
Tornado 攻略
请求处理程序和请求参数
重写 RequestHandler 的方法函数
重定向(redirect)
Cookie 和安全 Cookie
跨站伪造请求的防范
静态文件和主动式文件缓存
非阻塞式异步请求
异步 HTTP 客户端
第三方认证
调试模式和自动重载
生产环境下的部署
WSGI 和 Google AppEngine
注意事项和社区支持
FriendFeed使用了一款使用 Python 编写的,相对简单的 非阻塞式 Web 服务器。其应用程序使用的 Web 框架看起来有些像 web.py 或者 Google 的 webapp, 不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。
Tornado 就是我们在 FriendFeed 的 Web 服务器及其常用工具的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题,请参阅 The C10K problem )
以下是经典的 “Hello, world” 示例:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write(&Hello, world&)
application = tornado.web.Application([
(r&/&, MainHandler),
if __name__ == &__main__&:
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
查看下面的 Tornado 攻略以了解更多关于 tornado.web 包 的细节。
我们清理了 Tornado 的基础代码,减少了各模块之间的相互依存关系,所以理论上讲, 你可以在自己的项目中独立地使用任何模块,而不需要使用整个包。
下载和安装
自动安装: Tornado 已经列入 PyPI ,因此可以通过 pip 或者 easy_install 来安装。如果你没有安装 libcurl 的话,你需要将其单独安装到系统中。请参见下面的安装依赖一节。注意一点,使用 pip 或 easy_install 安装的 Tornado 并没有包含源代码中的 demo 程序。
手动安装: 下载 tornado-1.2.1.tar.gz
tar xvzf tornado-1.2.1.tar.gz
cd tornado-1.2.1
python setup.py build
sudo python setup.py install
Tornado 的代码托管在 GitHub 上面。对于 Python 2.6 以上的版本,因为标准库中已经包括了对 epoll 的支持,所以你可以不用 setup.py 编译安装,只要简单地将 tornado 的目录添加到 PYTHONPATH 就可以使用了。
Tornado 在 Python 2.5, 2.6, 2.7 中都经过了测试。要使用 Tornado 的所有功能,你需要安装 PycURL (7.18.2 或更高版本) 以及 simplejson (仅适用于Python 2.5,2.6 以后的版本标准库当中已经包含了对 JSON 的支持)。为方便起见,下面将列出 Mac OS X 和 Ubuntu 中的完整安装方式:
Mac OS X 10.6 (Python 2.6+)
sudo easy_install setuptools pycurl
Ubuntu Linux (Python 2.6+)
sudo apt-get install python-pycurl
Ubuntu Linux (Python 2.5)
sudo apt-get install python-de
正在加载中,请稍后...使用Python的Tornado框架实现一个Web端图书展示页面
作者:Kevin_Yang
字体:[ ] 类型:转载 时间:
Tornado是Python的一款高人气Web开发框架,这里我们来展示使用Python的Tornado框架实现一个Web端图书展示页面的实例,通过该实例可以清楚地学习到Tornado的模板使用及整个Web程序的执行流程.
首先,为什么选择Tornado:
1.高性能的网络库,这可以和gevent,twisted,libevent等做对。
提供了异步io支持,超时事件处理,在此基础上提供了tcpserver,httpclient,尤其是curlhttpclient,
在现有http客户端中肯定排第一。可以用来做爬虫,游戏服务器,据我所知业界已有使用tornado作为游戏服务器
2.web框架,这可以和django,flask对。
提供了路由,模板等web框架必备组件。与其他区别是tornado是异步的,天然适合长轮训,
这也是friendfeed发明tornado的原因,当前flask也可以支持,但必须借助gevent等
3.较为完备的http服务器,这点可以和nginx,apache对比,
但只支持http1.0,所以使用nginx做前段不仅是为了更好利用多核,也是让其支持http1.1
4.完备的wsgi服务器,这可以和gunicore,gevent wsgi server做对比,
也就是说可以让flask运行在tornado之上,让tornado加速flask
5.提供了完备的websocket支持,这让html5的游戏等提供了便利。
像知乎长轮训就是使用了websocket,但websocket手机支持的不是很好,
前段时间不得不使用定时ajax发送大量请求,期待手机浏览器赶快奋起直追
使用tornado创建一个简单的图书介绍页
好了,言归正传,下面我们来看一下这个图书介绍页的代码实现:
1.创建一个web服务的入口文件 blockmain.py
#coding:utf-8
import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.options
import os.path
import json
import urllib2
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render(
"index.html",
page_title = "Burt's Books & Home",
header_text = "Welcome to Burt's Books!",
books = ['细说php','python','PHP','小时代']
class HelloModule(tornado.web.UIModule):
def render(self):
return'&h1&I am yyx and this is an information from module hello!&/h1&'
class BookModule(tornado.web.UIModule):
def render(self,bookname):
doubanapi = r'/v2/book/'
searchapi = r'/v2/book/search?q='
searchurl = searchapi+bookname
searchresult = urllib2.urlopen(searchurl).read()
bookid = json.loads(searchresult)['books'][0]['id']
bookurl = doubanapi+bookid
injson = urllib2.urlopen(bookurl).read()
bookinfo = json.loads(injson)
return self.render_string('modules/book.html',book = bookinfo)
def embedded_javascript(self):
return "document.write(\"hi!\")"
def embedded_css(self):
return '''.book {background-color:#F5F5F5}
.book_body{color:red}
def html_body(self):
return '&script&document.write("Hello!")&/script&'
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers = [
(r'/',MainHandler),
template_path = os.path.join(os.path.dirname(__file__),'templates'),
static_path = os.path.join(os.path.dirname(__file__),'static'),
debug = True,
ui_modules={'Hello':HelloModule,'Book':BookModule}
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
说明一下,一些基本的MVC概念:
tornado也是通过pathinfo模式来匹配用户的输入来获得参数,然后再调用相应的处理函数,它是通过为各种匹配模式设定相应的class类来处理,比如我这里就是通过class MainHandler来处理来自/的get请求
MainHandler把请求render渲染到index.html,参数在index.html中通过{{参数}}来调用
2.建立相应的模板,先创建一个基础的父类main.html模板,创建templates目录,在它下面创建main.html,这个模板只是定义了最基础的网页框架,里面的具体内容由继承于它的子类来具体实现
&title&{{ page_title }}&/title&
&link rel="stylesheet" href="{{ static_url("css/style.css") }}" /&
&div id="container"&
{% block header %}&h1&Burt's Books&/h1&{% end %}
&div id="main"&
&div id="content"&
{% block body %}{% end %}
{% set mailLink = '&a href="mailto:"&Contact Us&/a&' %}
{% set script = '&script&alert("hello")&/script&' %}
{% block footer %}
For more information about our selection, hours or events, please email us at{% raw mailLink %}
&!-- {% raw script %} 这里将原样输出,也就是会弹一个框--&
&script src="{{ static_url("js/script.js") }}"&&/script&
这里是定义了一个主框架,其中里面的{% block header %}&h1&Burt's Books&/h1&{% end %}是为了子类模板的继承的块(block),当子类继承了这个main.html,具体这个块里写什么内容由子类来实现,不实现的话就使用父类的默认 值,如是这里的&h1&Burt's Books&/h1&,MainHandler类是render到一个index.html,那么接下来写一个index.html来继承这 个父类
{% extends "main.html" %}
{% block header %}
&h1&{{ header_text }}&/h1&
{% block body %}
&div id="hello"&
&p&Welcome to Burt's Books!&/p&
{% module Hello() %}
{% for book in books %}
{% module Book(book) %}
&p&...&/p&
简单简洁吧,这也是使用了继承的好处,不用再重复写父类的东西,只要实现父类的block内容即可
MainHandler类里的render方法中的参数
page_title = "Burt's Books | Home",
header_text = "Welcome to Burt's Books!",
books = ['细说php','python','PHP','小时代']
将会通过参数传送到这里来
tornado的模板里可以使用python的代码,加上{% %}当使用if for while等要使用{% end %}结尾
代码中{% module Book(book) %} 将会调用入口服务文件中的定义和'Book'所对应的模块
ui_modules={'Hello':HelloModule,'Book':BookModule} 也就是BookModule,查看上面的BookModule定义
class BookModule(tornado.web.UIModule):
def render(self,bookname):
doubanapi = r'/v2/book/'
searchapi = r'/v2/book/search?q='
searchurl = searchapi+bookname
searchresult = urllib2.urlopen(searchurl).read()
bookid = json.loads(searchresult)['books'][0]['id']
bookurl = doubanapi+bookid
injson = urllib2.urlopen(bookurl).read()
bookinfo = json.loads(injson)
return self.render_string('modules/book.html',book = bookinfo)
BookModule 继承自tornado.web.UIModule,UI模块的使用是最后render_string()方法来把一个对象渲染到一个模板中去,我这里简单 的使用了豆瓣的图书api,先通过search来查询一下包含关键词的图书信息,返回第一条图书的id,再使用book api来查询该图书的具体信息,将这个具体图书的信息render到对应的模板
在templates 目录下创建modules目录,再下创建一个book.html,这里是具体的book要显示的内容框架
&div class="book"&
&h3 class="book_title"&{{ book["title"] }}&/h3&
&a href="{{book['alt']}}" target="_blank"&&p&点击查看详情&/p&&/a&
{% if book["subtitle"] != "" %}
&h4 class="book_subtitle"&{{ book["subtitle"] }}&/h4&
&img src="{{ book["images"]["large"] }}" class="book_image"/&
&div class="book_details"&
&div class="book_date_released"&Released: {{ book["pubdate"]}}&/div&
&h5&Description:&/h5&
&div class="book_body"&{% raw book["summary"] %}&/div&
最后的文件目录结构应该是这样的
├── blockmain.py
└── templates
├── index.html
├── main.html
└── modules
└── book.html
程序的执行是这样的:
先通过路径‘/'来使用MainHandler类访问index.html----&index.html继承自 main.html----&index.html中的{% module Book(book) %}反过来查找blockmain.py中的Book对应的ui_modules----&ui_modules中将查询得到的book对象内容渲 染到modules下的book.html中,这样就把完整的内容呈现出来了,没有做前端…… 通过python blockmain.py启动服务,通过http://localhost:8000 来访问得到如下的网页
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 python3 web服务器 的文章

 

随机推荐