01.Tornado简介(tornadoweb)
ccwgpt 2024-10-14 08:42 29 浏览 0 评论
01.Tornado简介
Tornado是一个Python web框架和异步网络库,最初由FriendFeed开发。通过使用非阻塞网络I/O,Tornado可以扩展到数万个开放连接,使其成为长轮询、WebSockets和其他需要与每个用户建立长期连接的应用程序的理想选择。
Tornado大致可分为三个主要部分:
- web框架(包括创建web应用程序的子类RequestHandler和各种支持类)。
- HTTP的客户端和服务器端实现(HTTPServer和AsyncHTTPClient)。
- 一个异步网络库,包括IOLoop和IOStream类,它们是HTTP组件的构建块,也可用于实现其他协议。
Tornado web框架和HTTP服务器共同提供了WSGI的全栈替代方案。虽然可以将Tornado HTTP服务器用作其他WSGI框架的容器(WSGIContainer),但这种组合有局限性,要充分利用Tornado,您需要同时使用Tornado的web框架和HTTP服务器。
1.1线程与WSGI
Tornado不同于大多数Python web框架。它不是基于WSGI的,通常每个进程只运行一个线程。
虽然tornado.WSGI模块中提供了对WSGI的一些支持,但它不是开发的重点,大多数应用程序都应该直接使用tornado自己的接口(如tornado.web)来编写,而不是使用WSGI。
一般来说,Tornado代码不是线程安全的。Tornado中唯一可以从其他线程安全调用的方法是IOLoop.add_callback。您还可以使用IOLoop.run_in_executor在另一个线程上异步运行阻塞函数,但请注意,传递给run_in_excutor的函数应避免引用任何Tornado对象。run_in_executor是与阻塞代码交互的推荐方式。
1.2asyncio集成
Tornado与标准库asyncio模块集成在一起,并共享相同的事件循环(自Tornado 5.0以来默认)。一般来说,为asyncio设计的库可以与Tornado自由混合使用。
1.3安装
pip install tornado
Tornado列在PyPI中,可以用pip安装。请注意,源代码发行版包含以这种方式安装Tornado时不存在的演示应用程序,因此您可能希望下载源代码tar包的副本或克隆git存储库。
先决条件:Tornado 6.3需要Python 3.8或更高版本。以下可选软件包可能有用:
- pycurl由可选的tornado.curlhttpclient使用。需要Libcurl 7.22或更高版本。
- pycares是一种替代的非阻塞DNS解析器,可以在线程不合适时使用。
平台:Tornado专为类Unix平台设计,在支持epoll(Linux)、kqueue(BSD/macOS)或/dev/poll(Solaris)的系统上具有最佳性能和可扩展性。
Tornado也将在Windows上运行,尽管官方不支持或不建议在生产环境中使用此配置。Windows上缺少一些功能(包括多进程模式),可扩展性有限(尽管Tornado是在支持Windows的asyncio上构建的,但Tornado不使用Windows上可扩展网络所需的API)。
1.4示例
这是一个简单的 “Hello,world” Tornado网络应用程序示例:
import asyncio
import tornado
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
async def main():
app = make_app()
app.listen(8888)
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
这个例子没有使用Tornado的任何异步功能。
1.5异步和非阻塞I/O
实时网络功能要求每个用户都有一个长期空闲的连接。在传统的同步web服务器中,这意味着为每个用户分配一个线程,这可能非常昂贵。
为了最大限度地降低并发连接的成本,Tornado使用了单线程事件循环。这意味着所有应用程序代码都应该以异步和非阻塞为目标,因为一次只能有一个操作处于活动状态。
异步和非阻塞这两个术语密切相关,经常可以互换使用,但它们并不完全相同。
1.5.1阻塞
函数在返回之前等待发生某些事情时会阻塞。一个函数可能会因多种原因而阻塞:网络I/O、磁盘I/O、互斥等。事实上,每个函数在运行和使用CPU时都会阻塞,至少有一点点(举一个极端的例子,说明为什么CPU阻塞必须像其他类型的阻塞一样受到重视,可以考虑像bcrypt这样的密码散列函数,其设计使用数百毫秒的CPU时间,远远超过典型的网络或磁盘访问)。
函数在某些方面可以是阻塞的,在其他方面可以是非阻塞的。在Tornado的背景下,我们通常在网络I/O的背景下谈论阻塞,尽管各种阻塞都要尽量减少。
1.5.2异步
异步函数在完成之前返回,通常会在触发应用程序中的某些未来操作之前在后台进行一些工作(与正常的同步函数不同,后者在返回之前会做所有要做的事情)。异步接口有很多风格:
- 回调参数
- 返回占位符(Future、Promise、Deferred)
- 交付到队列
- 回调注册表(例如POSIX信号)
无论使用哪种类型的接口,异步函数与调用者的交互方式都是不同的;没有免费的方法可以使同步函数以对调用者透明的方式异步(像gevent这样的系统使用轻量级线程来提供与异步系统相当的性能,但它们实际上并没有使事情异步)。
Tornado中的异步操作通常返回占位符对象(Futures),但使用回调的IOLoop等一些低级组件除外。占位符对象(Futures)通常使用wait或yield关键字转换为结果。
1.5.3示例
以下是一个同步函数示例:
from tornado.httpclient import HTTPClient
def synchronous_fetch(url):
http_client = HTTPClient()
response = http_client.fetch(url)
return response.body
以下是作为本机协程异步重写的同一函数:
from tornado.httpclient import AsyncHTTPClient
async def asynchronous_fetch(url):
http_client = AsyncHTTPClient()
response = await http_client.fetch(url)
return response.body
或者为了与旧版本的Python兼容,使用tornado.gen模块:
from tornado.httpclient import AsyncHTTPClient
from tornado import gen
@gen.coroutine
def async_fetch_gen(url):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(url)
raise gen.Return(response.body)
协程有点神奇,但它们在内部的作用是这样的:
from tornado.concurrent import Future
def async_fetch_manual(url):
http_client = AsyncHTTPClient()
my_future = Future()
fetch_future = http_client.fetch(url)
def on_fetch(f):
my_future.set_result(f.result().body)
fetch_future.add_done_callback(on_fetch)
return my_future
请注意,协程在获取完成之前返回其Future。这就是协程异步的原因。
你可以用协程做任何事情,也可以通过传递回调对象来做,但协程通过让你以同步的方式组织代码,提供了一个重要的简化。这对于错误处理尤其重要,因为try/except块在协程中的工作方式与您所期望的一样,而这在回调中很难实现。
1.6协程
在Tornado中,推荐使用协程编写异步代码。协程使用Python的wait关键字来暂停和恢复执行,而不是一系列回调(在gevent等框架中看到的协作轻量级线程有时也被称为协程,但在Tornado中,所有协程都使用显式上下文开关,被称为异步函数)。
协程几乎和同步代码一样简单,但没有线程的开销。它们还通过减少可能发生上下文切换的地方的数量,使并发性更容易推理。
例子:
async def fetch_coroutine(url):
http_client = AsyncHTTPClient()
response = await http_client.fetch(url)
return response.body
1.6.1原生协程与装饰器协程
Python 3.5引入了async和wait关键字(使用这些关键字的函数也称为“原生协程”)。为了与旧版本的Python兼容,您可以使用tornado.gen.coroutine装饰器使用“装饰”或“基于yield”的协程。
只要有可能,建议使用原生协程。仅在需要与旧版本的Python兼容时使用装饰器协程。Tornado文档中的示例通常会使用原生形式。
这两种形式之间的翻译通常很简单:
# 装饰器: # 原生:
# Normal function declaration
# with decorator # "async def" keywords
@gen.coroutine
def a(): async def a():
# "yield" all async funcs # "await" all async funcs
b = yield c() b = await c()
# "return" and "yield"
# cannot be mixed in
# Python 2, so raise a
# special exception. # Return normally
raise gen.Return(b) return b
下面概述了这两种协程形式之间的其他差异。
- 原生协程:
- 通常更快。
- 可以使用async for和async with语句,这使一些模式变得简单得多。
- 除非你 await 或 yield,否则根本不执行。一旦调用,修饰后的协程就可以在“后台”开始运行。请注意,对于这两种协程,使用 wait 或 yield 都很重要,这样任何异常都有地方可抛出。
- 装饰器协程:
- 与consident.futures包进行额外集成,允许直接生成executor.submit的结果。对于原生协程,请改用IOLoop.run_in_executor。
- 通过生成列表或字典来支持等待多个对象的简略表达方式。在原生协程中使用tornado.gen.multi来实现这一点。
- 可以通过转换函数注册表支持与包括Twisted在内的其他软件包的集成。要在原生协程中访问此功能,请使用tornado.gen.convert_generated。
- 始终返回Future对象。原生协程返回一个不是Future的可唤醒对象。在Tornado中,两者大多可以互换。
相关推荐
- RACI矩阵:项目管理中的角色与责任分配利器
-
作者:赵小燕RACI矩阵RACI矩阵是项目管理中的一种重要工具,旨在明确团队在各个任务中的角色和职责。通过将每个角色划分为负责人、最终责任人、咨询人和知情人四种类型,RACI矩阵确保每个人都清楚自己...
- 在弱矩阵组织中,如何做好项目管理工作?「慕哲制图」
-
慕哲出品必属精品系列在弱矩阵组织中,如何做好项目管理工作?【慕哲制图】-------------------------------慕哲制图系列0:一图掌握项目、项目集、项目组合、P2、商业分析和NP...
- Scrum模式:每日站会(Daily Scrum)
-
定义每日站会(DailyScrum)是一个Scrum团队在进行Sprint期间的日常会议。这个会议的主要目的是为了应对Sprint计划中的不断变化,确保团队能够有效应对挑战并达成Sprint目标。为...
- 大家都在谈论的敏捷开发&Scrum,到底是什么?
-
敏捷开发作为一种开发模式,近年来深受研发团队欢迎,与瀑布式开发相比,敏捷开发更轻量,灵活性更高,在当下多变环境下,越来越多团队选择敏捷开发。什么是敏捷?敏捷是一种在不确定和变化的环境中,通过创造和响应...
- 敏捷与Scrum是什么?(scrum敏捷开发是什么)
-
敏捷是一种思维模式和哲学,它描述了敏捷宣言中的一系列原则。另一方面,Scrum是一个框架,规定了实现这种思维方式的角色,事件,工件和规则/指南。换句话说,敏捷是思维方式,Scrum是规定实施敏捷哲学的...
- 敏捷项目管理与敏捷:Scrum流程图一览
-
敏捷开发中的Scrum流程通常可以用一个简单的流程图来表示,以便更清晰地展示Scrum框架的各个阶段和活动。以下是一个常见的Scrum流程图示例:这个流程图涵盖了Scrum框架的主要阶段和活动,其中包...
- Mockito 的最佳实践(mock方法)
-
记得以前面试的时候,面试官问我,平常开发过程中自己会不会测试?我回答当然会呀,自己写的代码怎么不测呢。现在想想我好像误会他的意思了,他应该是想问我关于单元测试,集成测试以及背后相关的知识,然而当时说到...
- EffectiveJava-5-枚举和注解(java枚举的作用与好处)
-
用enum代替int常量1.int枚举:引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员,这种方法叫做int枚举模式。int枚举模式是类型不安全的,例如下面两组常量:性别和动物种...
- Maven 干货 全篇共:28232 字。预计阅读时间:110 分钟。建议收藏!
-
Maven简介Maven这个词可以翻译为“知识的积累”,也可以翻译为“专家”或“内行”。Maven是一个跨平台的项目管理工具。主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。仔...
- Java单元测试框架PowerMock学习(java单元测试是什么意思)
-
前言高德的技术大佬在谈论方法论时说到:“复杂的问题要简单化,简单的问题要深入化。”这句话让我感触颇深,这何尝不是一套编写代码的方法——把一个复杂逻辑拆分为许多简单逻辑,然后把每一个简单逻辑进行深入实现...
- Spring框架基础知识-第六节内容(Spring高级话题)
-
Spring高级话题SpringAware基本概念Spring的依赖注入的最大亮点是你所有的Bean对Spring容器的存在是没有意识的。但是在实际的项目中,你的Bean必须要意识到Spring容器...
- Java单元测试浅析(JUnit+Mockito)
-
作者:京东物流秦彪1.什么是单元测试(1)单元测试环节:测试过程按照阶段划分分为:单元测试、集成测试、系统测试、验收测试等。相关含义如下:1)单元测试:针对计算机程序模块进行输出正确性检验工作...
- 揭秘Java代码背后的质检双侠:JUnit与Mockito!
-
你有没有发现,现在我们用的手机App、逛的网站,甚至各种智能设备,功能越来越复杂,但用起来却越来越顺畅,很少遇到那种崩溃、卡顿的闹心事儿?这背后可不是程序员一拍脑袋写完代码就完事儿了!他们需要一套严谨...
- 单元测试框架哪家强?Junit来帮忙!
-
大家好,在前面的文章中,给大家介绍了以注解和XML的方式分别实现IOC和依赖注入。并且我们定义了一个测试类,通过测试类来获取到了容器中的Bean,具体的测试类定义如下:@Testpublicvoid...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- mfc框架 (52)
- abb框架断路器 (48)
- ui自动化框架 (47)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- ppt框架 (48)
- 内联框架 (52)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)