PRF:20180614 An introduction to the Tornado Python web app framework.md

@MjSeven
This commit is contained in:
Xingyu.Wang 2019-02-09 18:03:57 +08:00
parent 03fecee832
commit 1a1395ec19

View File

@ -1,28 +1,29 @@
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: reviewer: (wxy)
[#]: publisher: ( )
[#]: subject: (An introduction to the Tornado Python web app framework)
[#]: via: (https://opensource.com/article/18/6/tornado-framework)
[#]: author: (Nicholas Hunt-Walker https://opensource.com/users/nhuntwalker)
[#]: url: ( )
Python Web 框架 Tornado 简介
Python Web 应用程序 Tornado 框架简介
======
在比较 Python 框架的系列文章的第三部分中,我们来了解 Tornado它是为处理异步进程而构建的。
> 在比较 Python 框架的系列文章的第三部分中,我们来了解 Tornado它是为处理异步进程而构建的。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tornado.png?itok=kAa3eXIU)
在这个由四部分组成的系列文章的前两篇中,我们介绍了 [Pyramid][1] 和 [Flask][2] Web 框架。我们已经构建了两次相同的应用程序,看到了一个完全的 DIY 框架和包含更多电池的框架之间的异同。
在这个由四部分组成的系列文章的前两篇中,我们介绍了 [Pyramid][1] 和 [Flask][2] Web 框架。我们已经构建了两次相同的应用程序,看到了一个完整的 DIY 框架和包含了更多功能的框架之间的异同。
现在让我们来看看另一个稍微不同的选[Tornado 框架][3]。Tornado 在很大程度上与 Flask 一样简单但有一个主要区别Tornado 是专门为处理异步进程而构建的。在我们本系列所构建的应用程序中,这种特殊的酱料(译注:这里意思是 Tornado 的异步功能)并不是非常有用,但我们将看到在哪里可以使用它,以及它在更一般的情况下是如何工作的。
现在让我们来看看另一个稍微不同的选[Tornado 框架][3]。Tornado 在很大程度上与 Flask 一样简单但有一个主要区别Tornado 是专门为处理异步进程而构建的。在我们本系列所构建的应用程序中,这种特殊的酱料(LCTT 译注:这里意思是 Tornado 的异步功能)在我们构建的 app 中并不是非常有用,但我们将看到在哪里可以使用它,以及它在更一般的情况下是如何工作的。
让我们继续前两篇文章中设置的流程,首先从处理设置和配置
让我们继续前两篇文章中模式,首先从处理设置和配置开始
### Tornado 启动和配置
如果你一直关注这个系列,那么第一步应该对你来说习以为常。
```
$ mkdir tornado_todo
$ cd tornado_todo
@ -32,6 +33,7 @@ $ pipenv shell
```
创建一个 `setup.py` 文件来安装我们的应用程序相关的东西:
```
(tornado-someHash) $ touch setup.py
# setup.py
@ -61,6 +63,7 @@ setup(
```
因为 Tornado 不需要任何外部配置,所以我们可以直接编写 Python 代码来让程序运行。让我们创建 `todo` 目录,并用需要的前几个文件填充它。
```
todo/
    __init__.py
@ -68,7 +71,18 @@ todo/
    views.py
```
就像 Flask 和 Pyramid 一样Tornado 也有一些基本配置,将放在 `__init__.py` 中。从 `tornado.web` 中,我们将导入 `Application` 对象,它将处理路由和视图的连接,包括数据库(当我们谈到那里时再说)以及运行 Tornado 应用程序所需的其它额外设置。
就像 Flask 和 Pyramid 一样Tornado 也有一些基本配置,放在 `__init__.py` 中。从 `tornado.web` 中,我们将导入 `Application` 对象,它将处理路由和视图的连接,包括数据库(当我们谈到那里时再说)以及运行 Tornado 应用程序所需的其它额外设置。
```
# __init__.py
from tornado.web import Application
def main():
"""Construct and serve the tornado application."""
app = Application()
```
像 Flask 一样Tornado 主要是一个 DIY 框架。当构建我们的 app 时,我们必须设置该应用实例。因为 Tornado 用它自己的 HTTP 服务器来提供该应用,我们必须设置如何提供该应用。首先,在 `tornado.options.define` 中定义要监听的端口。然后我们实例化 Tornado 的 `HTTPServer`,将该 `Application` 对象的实例作为参数传递给它。
```
# __init__.py
@ -109,13 +123,13 @@ def main():
    IOLoop.current().start()
```
我喜欢某种形式的 `print` 声明,告诉我什么时候应用程序正在提供服务,我就是这样子。如果你愿意,可以不使用 `print`
我喜欢某种形式的 `print` 语句,来告诉我什么时候应用程序正在提供服务,这是我的习惯。如果你愿意,可以不使用 `print`
我们以 `IOLoop.current().start()` 开始我们的 I/O 循环。让我们进一步讨论输入,输出和异步性。
### Python 中的异步和 I/O 循环的基础知识
请允许我提前说明,我绝对,肯定,肯定并且安心地说不是异步编程方面的专家。就像我写的所有内容一样,接下来的内容源于我对这个概念的理解的局限性。因为我是人,可能有很深很深的缺陷。
请允许我提前说明,我绝对,肯定,一定并且放心地说不是异步编程方面的专家。就像我写的所有内容一样,接下来的内容源于我对这个概念的理解的局限性。因为我是人,可能有很深很深的缺陷。
异步程序的主要问题是:
@ -123,7 +137,7 @@ def main():
* 数据如何出去?
* 什么时候可以在不占用我全部注意力情况下运行某个过程?
由于[全局解释器锁][4]GILPython 被设计为一种单线程语言。对于 Python 程序必须执行的每个任务,其线程执行的全部注意力都集中在该任务的持续时间内。我们的 HTTP 服务器是用 Python 编写的,因此,当接收到数据(如 HTTP 请求)时,服务器的唯一关心的是传入的数据。这意味着,在大多数情况下,无论是程序需要运行还是处理数据,程序都将完全消耗服务器的执行线程,阻止接收其它可能的数据,直到服务器完成它需要做的事情。
由于[全局解释器锁][4]GILPython 被设计为一种[单线程][5]语言。对于 Python 程序必须执行的每个任务,其线程执行的全部注意力都集中在该任务的持续时间内。我们的 HTTP 服务器是用 Python 编写的,因此,当接收到数据(如 HTTP 请求)时,服务器的唯一关心的是传入的数据。这意味着,在大多数情况下,无论是程序需要运行还是处理数据,程序都将完全消耗服务器的执行线程,阻止接收其它可能的数据,直到服务器完成它需要做的事情。
在许多情况下,这不是太成问题。典型的 Web 请求,响应周期只需要几分之一秒。除此之外,构建 HTTP 服务器的套接字可以维护待处理的传入请求的积压。因此,如果请求在该套接字处理其它内容时进入,则它很可能只是在处理之前稍微排队等待一会。对于低到中等流量的站点,几分之一秒的时间并不是什么大问题,你可以使用多个部署的实例以及 [NGINX][6] 等负载均衡器来为更大的请求负载分配流量。
@ -182,9 +196,9 @@ def main():
尽管经历了在 Python 中讨论异步的所有麻烦,我们还是决定暂不使用它。先来编写一个基本的 Tornado 视图。
与我们在 Flask 和 Pyramid 实现中看到的基于函数的视图不同Tornado 的视图都是基于类的。这意味着我们将不在使用单独的独立的函数来规定如何处理请求。相反,传入的 HTTP 请求将被捕获并将其分配为我们定义的类的一个属性。然后,它的方法将处理相应的请求类型。
与我们在 Flask 和 Pyramid 实现中看到的基于函数的视图不同Tornado 的视图都是基于类的。这意味着我们将不在使用单独的独立的函数来规定如何处理请求。相反,传入的 HTTP 请求将被捕获并将其分配为我们定义的类的一个属性。然后,它的方法将处理相应的请求类型。
让我们从一个基本的视图开始,即在屏幕上打印 "Hello, World"。我们为 Tornado 应用程序构造的每个基于类的视图都必须继承 `tornado.web` 中的 `RequestHandler` 对象。这将设置我们需要(但不想写)的所有底层逻辑来接收请求,同时构造正确格式的 HTTP 响应。
让我们从一个基本的视图开始,即在屏幕上打印 “Hello, World”。我们为 Tornado 应用程序构造的每个基于类的视图都必须继承 `tornado.web` 中的 `RequestHandler` 对象。这将设置我们需要(但不想写)的所有底层逻辑来接收请求,同时构造正确格式的 HTTP 响应。
```
from tornado.web import RequestHandler
@ -197,7 +211,7 @@ class HelloWorld(RequestHandler):
        self.write("Hello, world!")
```
因为我们要处理 `GET` 请求,所以我们声明(实际上是重写) `get` 方法。我们提供文本或 JSON 可序列化对象,用 `self.write` 写入响应体。之后,我们让 `RequestHandler` 来做在发送响应之前必须完成的其它工作。
因为我们要处理 `GET` 请求,所以我们声明(实际上是重写) `get` 方法。我们提供文本或 JSON 可序列化对象,用 `self.write` 写入响应体。之后,我们让 `RequestHandler` 来做在发送响应之前必须完成的其它工作。
就目前而言,此视图与 Tornado 应用程序本身并没有实际连接。我们必须回到 `__init__.py`,并稍微更新 `main` 函数。以下是新的内容:
@ -226,15 +240,15 @@ def main():
我们将 `views.py` 文件中的 `HelloWorld` 视图导入到脚本 `__init__.py` 的顶部。然后我们添加了一个路由-视图对应的列表,作为 `Application` 实例化的第一个参数。每当我们想要在应用程序中声明一个路由时,它必须绑定到一个视图。如果需要,可以对多个路由使用相同的视图,但每个路由必须有一个视图。
我们可以通过在 `setup.py` 中启用的 `serve_app` 命令来运行应用程序,从而确保这一切都能正常工作。查看 `http://localhost:8888/` 并看到它显示 "Hello, world!"
我们可以通过在 `setup.py` 中启用的 `serve_app` 命令来运行应用程序,从而确保这一切都能正常工作。查看 `http://localhost:8888/` 并看到它显示 “Hello, world!”
当然,在这个领域中我们还能做更多,也将做更多,但现在让我们来讨论模型吧。
### 连接数据库
如果我们想要保留数据,我们需要连接数据库。与 Flask 一样,我们将使用一个特定于框架的 SQLAchemy 变体,名为 [tornado-sqlalchemy][7]。
如果我们想要保留数据,需要连接数据库。与 Flask 一样,我们将使用一个特定于框架的 SQLAchemy 变体,名为 [tornado-sqlalchemy][7]。
为什么要使用它而不是 [SQLAlchemy][8] 呢?好吧,其实 `tornado-sqlalchemy` 具有简单 SQLAlchemy 的所有优点,因此我们仍然可以使用通用的 `Base` 声明模型,并使用我们习以为常的所有列数据类型和关系。除了我们已经从习惯中了解到的,`tornado-sqlalchemy` 还为其数据库查询功能提供了一种可访问的异步模式,专门用于与 Tornado 现有的 I/O 循环一起工作。
为什么要使用它而不是 [SQLAlchemy][8] 呢?好吧,其实 `tornado-sqlalchemy` 具有简单 SQLAlchemy 的所有优点,因此我们仍然可以使用通用的 `Base` 声明模型,并使用我们习以为常的所有列数据类型和关系。除了我们已经惯常了解到的,`tornado-sqlalchemy` 还为其数据库查询功能提供了一种可访问的异步模式,专门用于与 Tornado 现有的 I/O 循环一起工作。
我们通过将 `tornado-sqlalchemy``psycopg2` 添加到 `setup.py` 到所需包的列表并重新安装包来创建环境。在 `models.py` 中,我们声明了模型。这一步看起来与我们在 Flask 和 Pyramid 中已经看到的完全一样,所以我将跳过全部声明,只列出了 `Task` 模型的必要部分。
@ -463,7 +477,7 @@ class TaskListView(BaseView):
                })
```
这里的第一个主要部分是 `@coroutine` 装饰器,它从 `tornado.gen` 导入。任何具有与调用堆栈的正常流程不同步的部分的 Python 可调用实际上是“协程”。一个可以与其它协程一起运行的协程。在我的家务劳动的例子中,几乎所有的家务活都是一个共同的例行协程。有些阻止了例行协程(例如,给地板吸尘),但这种例行协程只会阻碍我开始或关心其它任何事情的能力。它没有阻止已经启动的任何其他协程继续进行。
这里的第一个主要部分是 `@coroutine` 装饰器,它从 `tornado.gen` 导入。任何具有与调用堆栈的正常流程不同步的 Python 可调用部分实际上是“协程”,即一个可以与其它协程一起运行的协程。在我的家务劳动的例子中,几乎所有的家务活都是一个共同的例行协程。有些阻止了例行协程(例如,给地板吸尘),但这种例行协程只会阻碍我开始或关心其它任何事情的能力。它没有阻止已经启动的任何其他协程继续进行。
Tornado 提供了许多方法来构建一个利用协程的应用程序,包括允许我们设置函数调用锁,同步异步协程的条件,以及手动修改控制 I/O 循环的事件系统。
@ -525,9 +539,9 @@ def post(self, username):
在我们继续浏览这些 Web 框架时,我们开始看到它们都可以有效地处理相同的问题。对于像这样的待办事项列表,任何框架都可以完成这项任务。但是,有些 Web 框架比其它框架更适合某些工作,这具体取决于对你来说什么“更合适”和你的需求。
虽然 Tornado 显然能够处理 Pyramid 或 Flask 可以处理的相同工作,但将它用于这样的应用程序实际上是一种浪费,这就像开车从家走一个街区(to 校正:这里意思应该是从家开始走一个街区只需步行即可)。是的,它可以完成“旅行”的工作,但短途旅行不是你选择汽车而不是自行车或者使用双脚的原因。
虽然 Tornado 显然和 Pyramid 或 Flask 一样可以处理相同工作,但将它用于这样的应用程序实际上是一种浪费,这就像开车从家走一个街区(LCTT 译注:这里意思应该是从家开始走一个街区只需步行即可)。是的,它可以完成“旅行”的工作,但短途旅行不是你选择汽车而不是自行车或者使用双脚的原因。
根据文档Tornado 被称为 “Python Web 框架和异步网络库”。在 Python Web 框架生态系统中很少有人喜欢它。如果你尝试完成的工作需要(或将从中获益)以任何方式形状或形式的异步性,使用 Tornado。如果你的应用程序需要处理多个长期连接同时又不想牺牲太多性能选择 Tornado。如果你的应用程序是多个应用程序并且需要线程感知以准确处理数据使用 Tornado。这是它最有效的地方。
根据文档Tornado 被称为 “Python Web 框架和异步网络库”。在 Python Web 框架生态系统中很少有人喜欢它。如果你尝试完成的工作需要(或将从中获益)以任何方式形状或形式的异步性,使用 Tornado。如果你的应用程序需要处理多个长期连接同时又不想牺牲太多性能选择 Tornado。如果你的应用程序是多个应用程序并且需要线程感知以准确处理数据使用 Tornado。这是它最有效的地方。
用你的汽车做“汽车的事情”,使用其他交通工具做其他事情。
@ -535,13 +549,10 @@ def post(self, username):
谈到使用合适的工具来完成合适的工作,在选择框架时,请记住应用程序的范围和规模,包括现在和未来。到目前为止,我们只研究了适用于中小型 Web 应用程序的框架。本系列的下一篇也是最后一篇将介绍最受欢迎的 Python 框架之一 Django它适用于可能会变得更大的大型应用程序。同样尽管它在技术上能够并且将会处理待办事项列表问题但请记住这不是它的真正用途。我们仍然会通过它来展示如何使用它来构建应用程序但我们必须牢记框架的意图以及它是如何反映在架构中的
  * **Flask:** 适用于小型,简单的项目。它可以使我们轻松地构建视图并将它们快速连接到路由,它可以简单地封装在一个文件中。
  * **Pyramid:** 适用于可能增长的项目。它包含一些配置来启动和运行。应用程序组件的独立领域可以很容易地划分并构建到任意深度,而不会忽略中央应用程序。
  * **Tornado:** 适用于受益于精确和有意识的 I/O 控制的项目。它允许协程,并轻松公开可以控制如何接收请求或发送响应以及何时发生这些操作的方法。
  * **Django:**(我们将会看到)意味着可能会变得更大的东西。它有着非常庞大的生态系统,包括大量插件和模块。它非常有主见的配置和管理,以保持所有不同部分在同一条线上。
* **Flask** 适用于小型,简单的项目。它可以使我们轻松地构建视图并将它们快速连接到路由,它可以简单地封装在一个文件中。
* **Pyramid** 适用于可能增长的项目。它包含一些配置来启动和运行。应用程序组件的独立领域可以很容易地划分并构建到任意深度,而不会忽略中央应用程序。
* **Tornado** 适用于受益于精确和有意识的 I/O 控制的项目。它允许协程,并轻松公开可以控制如何接收请求或发送响应以及何时发生这些操作的方法。
* **Django**:(我们将会看到)意味着可能会变得更大的东西。它有着非常庞大的生态系统,包括大量插件和模块。它非常有主见的配置和管理,以保持所有不同部分在同一条线上。
无论你是从本系列的第一篇文章开始阅读,还是稍后才加入的,都要感谢阅读!请随意留下问题或意见。下次再见时,我手里会拿着 Django。
@ -549,7 +560,7 @@ def post(self, username):
我必须把功劳归于它应得的地方,非常感谢 [Guido van Rossum][12],不仅仅是因为他创造了我最喜欢的编程语言。
在 [PyCascades 2018][13] 期间,我很幸运的不仅了基于这个文章系列的演讲,而且还被邀请参加了演讲者的晚宴。整个晚上我都坐在 Guido 旁边,不停地问他问题。其中一个问题是,在 Python 中异步到底是如何工作的,但他没有一点大惊小怪,而是花时间向我解释,让我开始理解这个概念。他后来[推特给我][14]发了一条消息:是用于学习异步 Python 的广阔资源。我随后在三个月内阅读了三次然后写了这篇文章。你真是一个非常棒的人Guido
在 [PyCascades 2018][13] 期间,我很幸运的不仅了基于这个文章系列的演讲,而且还被邀请参加了演讲者的晚宴。整个晚上我都坐在 Guido 旁边,不停地问他问题。其中一个问题是,在 Python 中异步到底是如何工作的,但他没有一点大惊小怪,而是花时间向我解释,让我开始理解这个概念。他后来[推特给我][14]发了一条消息:是用于学习异步 Python 的广阔资源。我随后在三个月内阅读了三次然后写了这篇文章。你真是一个非常棒的人Guido
--------------------------------------------------------------------------------
@ -558,7 +569,7 @@ via: https://opensource.com/article/18/6/tornado-framework
作者:[Nicholas Hunt-Walker][a]
选题:[lujun9972][b]
译者:[MjSeven](https://github.com/MjSeven)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出