# SOME DESCRIPTIVE TITLE. # Copyright (C) 2009-2020, Marcel Hellkamp # This file is distributed under the same license as the Bottle package. # # Translators: msgid "" msgstr "" "Project-Id-Version: bottle\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-12-31 18:35+0100\n" "PO-Revision-Date: 2017-09-21 22:57+0000\n" "Last-Translator: Thiago Avelino \n" "Language-Team: Chinese (China) (http://www.transifex.com/bottle/bottle/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" #: ../../async.rst:2 msgid "Primer to Asynchronous Applications" msgstr "异步应用入门" #: ../../async.rst:4 msgid "" "Asynchronous design patterns don't mix well with the synchronous nature of " "`WSGI `_. This is why most " "asynchronous frameworks (tornado, twisted, ...) implement a specialized API " "to expose their asynchronous features. Bottle is a WSGI framework and shares" " the synchronous nature of WSGI, but thanks to the awesome `gevent project " "`_, it is still possible to write asynchronous " "applications with bottle. This article documents the usage of Bottle with " "Asynchronous WSGI." msgstr "异步设计模式和 `WSGI `_ 的同步本质并不能很好地兼容。这就是为什么大部分的异步框架(tornado, twisted, ...)都实现了专有的API来暴露它们的异步特征。Bottle是一个WSGI框架,也继承了WSGI的同步本质,但是谢谢优秀的 `gevent项目 `_ ,我们可以使用Bottle来编写异步应用。这份文档介绍了在Bottle中如何使用异步WSGI。" #: ../../async.rst:7 msgid "The Limits of Synchronous WSGI" msgstr "同步WSGI的限制" #: ../../async.rst:9 msgid "" "Briefly worded, the `WSGI specification (pep 3333) " "`_ defines a request/response " "circle as follows: The application callable is invoked once for each request" " and must return a body iterator. The server then iterates over the body and" " writes each chunk to the socket. As soon as the body iterator is exhausted," " the client connection is closed." msgstr "简单来说, `WSGI标准 (pep 3333) `_ 定义了下面这一个request/response的循环:每次请求到达的时候,应用中的callable会被调用一次,返回一个主体iterator。接着服务器会遍历该主体,分块写入socket。遍历完整个主体,就关闭客户端的连接。" #: ../../async.rst:11 msgid "" "Simple enough, but there is a snag: All this happens synchronously. If your " "application needs to wait for data (IO, sockets, databases, ...), it must " "either yield empty strings (busy wait) or block the current thread. Both " "solutions occupy the handling thread and prevent it from answering new " "requests. There is consequently only one ongoing request per thread." msgstr "足够简单,但是存在一个小问题:所有这些都是同步的。如果你的应用需要等待数据(IO, socket, 数据库, ...),除了返回一个空字符串(忙等),就只能阻塞当前线程。两种办法都会占用当前线程,导致线程不能处理新的请求,只能处理当前的一个请求。" #: ../../async.rst:13 msgid "" "Most servers limit the number of threads to avoid their relatively high " "overhead. Pools of 20 or less threads are common. As soon as all threads are" " occupied, any new connection is stalled. The server is effectively dead for" " everyone else. If you want to implement a chat that uses long-polling ajax " "requests to get real-time updates, you'd reach the limited at 20 concurrent " "connections. That's a pretty small chat." msgstr "大部分服务器都限制了线程的数量,避免伴随它们而来的资源消耗。常见的是一个线程池,内有20个或更少数量的线程。一旦所有的线程都被占用了,任何新的请求都会阻塞。事实上,对于其他人来说,服务器已经宕机了。如果你想实现一个聊天程序,使用ajax轮询来获取实时消息,很快你就会受到线程数量的限制。这样能同时服务的用户就太少了。" #: ../../async.rst:16 msgid "Greenlets to the rescue" msgstr "救星,Greenlet" #: ../../async.rst:18 msgid "" "Most servers limit the size of their worker pools to a relatively low number" " of concurrent threads, due to the high overhead involved in switching " "between and creating new threads. While threads are cheap compared to " "processes (forks), they are still expensive to create for each new " "connection." msgstr "大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和创建进程(fork)的代价比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。" #: ../../async.rst:20 msgid "" "The `gevent `_ module adds *greenlets* to the mix. " "Greenlets behave similar to traditional threads, but are very cheap to " "create. A gevent-based server can spawn thousands of greenlets (one for each" " connection) with almost no overhead. Blocking individual greenlets has no " "impact on the servers ability to accept new requests. The number of " "concurrent connections is virtually unlimited." msgstr "`gevent `_ 模块添加了 *greenlet* 的支持。greenlet和传统的线程类似,但其创建只需消耗很少的资源。基于gevent的服务器可以生成成千上万的greenlet,为每个连接分配一个greenlet也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。" #: ../../async.rst:22 msgid "" "This makes creating asynchronous applications incredibly easy, because they " "look and feel like synchronous applications. A gevent-based server is " "actually not asynchronous, but massively multi-threaded. Here is an " "example::" msgstr "这令创建异步应用难以置信的简单,因为它们看起来很想同步程序。基于gevent服务器实际上不是异步的,是大规模多线程。下面是一个例子。" #: ../../async.rst:39 msgid "" "The first line is important. It causes gevent to monkey-patch most of " "Python's blocking APIs to not block the current thread, but pass the CPU to " "the next greenlet instead. It actually replaces Python's threading with " "gevent-based pseudo-threads. This is why you can still use ``time.sleep()`` " "which would normally block the whole thread. If you don't feel comfortable " "with monkey-patching python built-ins, you can use the corresponding gevent " "functions (``gevent.sleep()`` in this case)." msgstr "第一行很重要。它让gevent monkey-patch了大部分Python的阻塞API,让它们不阻塞当前线程,将CPU让给下一个greenlet。它实际上用基于gevent的伪线程替换了Python的线程。这就是你依然可以使用 ``time.sleep()`` 这个照常来说会阻塞线程的函数。如果这种monkey-patch的方式感令你感到不舒服,你依然可以使用gevent中相应的函数 ``gevent.sleep()`` 。" #: ../../async.rst:41 msgid "" "If you run this script and point your browser to " "``http://localhost:8080/stream``, you should see `START`, `MIDDLE`, and " "`END` show up one by one (rather than waiting 8 seconds to see them all at " "once). It works exactly as with normal threads, but now your server can " "handle thousands of concurrent requests without any problems." msgstr "如果你运行了上面的代码,接着访问 ``http://localhost:8080/stream`` ,你可看到 `START`, `MIDDLE`, 和 `END` 这几个字样依次出现(用时大约8秒)。它像普通的线程一样工作,但是现在你的服务器能同时处理成千上万的连接了。" #: ../../async.rst:45 msgid "" "Some browsers buffer a certain amount of data before they start rendering a " "page. You might need to yield more than a few bytes to see an effect in " "these browsers. Additionally, many browsers have a limit of one concurrent " "connection per URL. If this is the case, you can use a second browser or a " "benchmark tool (e.g. `ab` or `httperf`) to measure performance." msgstr "一些浏览器在开始渲染一个页面之前,会缓存确定容量的数据。在这些浏览器上,你需要返回更多的数据才能看到效果。另外,很多浏览器限制一个URL只使用一个连接。在这种情况下,你可以使用另外的浏览器,或性能测试工具(例如: `ab` 或 `httperf` )来测试性能。" #: ../../async.rst:52 msgid "Event Callbacks" msgstr "事件回调函数" #: ../../async.rst:54 msgid "" "A very common design pattern in asynchronous frameworks (including tornado, " "twisted, node.js and friends) is to use non-blocking APIs and bind callbacks" " to asynchronous events. The socket object is kept open until it is closed " "explicitly to allow callbacks to write to the socket at a later point. Here " "is an example based on the `tornado library " "`_::" msgstr "异步框架的常见设计模式(包括 tornado, twisted, node.js 和 friends),是使用非阻塞的API,绑定回调函数到异步事件上面。在显式地关闭之前,socket会保持打开,以便稍后回调函数往socket里面写东西。下面是一个基于 `tornado `_ 的例子。" #: ../../async.rst:63 msgid "" "The main benefit is that the request handler terminates early. The handling " "thread can move on and accept new requests while the callbacks continue to " "write to sockets of previous requests. This is how these frameworks manage " "to process a lot of concurrent requests with only a small number of OS " "threads." msgstr "主要的好处就是MainHandler能早早结束,在回调函数继续写socket来响应之前的请求的时候,当前线程能继续接受新的请求。这样就是为什么这类框架能同时处理很多请求,只使用很少的操作系统线程。" #: ../../async.rst:65 msgid "" "With Gevent+WSGI, things are different: First, terminating early has no " "benefit because we have an unlimited pool of (pseudo)threads to accept new " "connections. Second, we cannot terminate early because that would close the " "socket (as required by WSGI). Third, we must return an iterable to conform " "to WSGI." msgstr "对于Gevent和WSGI来说,情况就不一样了:首先,早早结束没有好处,因为我们的(伪)线程池已经没有限制了。第二,我们不能早早结束,因为这样会关闭socket(WSGI要求如此)。第三,我们必须返回一个iterator,以遵守WSGI的约定。" #: ../../async.rst:67 msgid "" "In order to conform to the WSGI standard, all we have to do is to return a " "body iterable that we can write to asynchronously. With the help of " "`gevent.queue `_, we can *simulate*" " a detached socket and rewrite the previous example as follows::" msgstr "为了遵循WSGI规范,我们只需返回一个iterable的实体,异步地将其写回客户端。在 `gevent.queue `_ 的帮助下,我们可以 *模拟* 一个脱管的socket,上面的例子可写成这样。" #: ../../async.rst:78 msgid "" "From the server perspective, the queue object is iterable. It blocks if " "empty and stops as soon as it reaches ``StopIteration``. This conforms to " "WSGI. On the application side, the queue object behaves like a non-blocking " "socket. You can write to it at any time, pass it around and even start a new" " (pseudo)thread that writes to it asynchronously. This is how long-polling " "is implemented most of the time." msgstr "从服务器的角度来看,queue对象是iterable的。如果为空,则阻塞,一旦遇到 ``StopIteration`` 则停止。这符合WSGI规范。从应用的角度来看,queue对象表现的像一个不会阻塞socket。你可以在任何时刻写入数据,pass it around,甚至启动一个新的(伪)线程,异步写入。这是在大部分情况下,实现长轮询。" #: ../../async.rst:82 msgid "Finally: WebSockets" msgstr "最后: WebSockets" #: ../../async.rst:84 msgid "" "Lets forget about the low-level details for a while and speak about " "WebSockets. Since you are reading this article, you probably know what " "WebSockets are: A bidirectional communication channel between a browser " "(client) and a web application (server)." msgstr "让我们暂时忘记底层的细节,来谈谈WebSocket。既然你正在阅读这篇文章,你有可能已经知道什么是WebSocket了,一个在浏览器(客户端)和Web应用(服务端)的双向的交流通道。" #: ../../async.rst:86 msgid "" "Thankfully the `gevent-websocket `_ package does all the hard work for us. Here is a simple " "WebSocket endpoint that receives messages and just sends them back to the " "client::" msgstr "感谢 `gevent-websocket `_ 包帮我们做的工作。下面是一个WebSocket的简单例子,接受消息然后将其发回客户端。" #: ../../async.rst:111 msgid "" "The while-loop runs until the client closes the connection. You get the idea" " :)" msgstr "while循环直到客户端关闭连接的时候才会终止。You get the idea :)" #: ../../async.rst:113 msgid "The client-site JavaScript API is really straight forward, too::" msgstr "客户端的JavaScript API也十分简洁明了::"