### Navigation
- [index](# "General Index")
- [modules](# "Python Module Index") |
- [next](# "Queue example - a concurrent web spider") |
- [previous](# "Asynchronous and non-Blocking I/O") |
- [Tornado 4.4.dev1 documentation](#) »
- [User's guide](#) »
# Coroutines
**Coroutines** are the recommended way to write asynchronous code inTornado. Coroutines use the Python `yield` keyword to suspend andresume execution instead of a chain of callbacks (cooperativelightweight threads as seen in frameworks like [gevent](http://www.gevent.org) [http://www.gevent.org] are sometimes called coroutines as well, butin Tornado all coroutines use explicit context switches and are calledas asynchronous functions).
Coroutines are almost as simple as synchronous code, but without theexpense of a thread. They also [make concurrency easier](https://glyph.twistedmatrix.com/2014/02/unyielding.html) [https://glyph.twistedmatrix.com/2014/02/unyielding.html] to reasonabout by reducing the number of places where a context switch canhappen.
Example:
~~~
from tornado import gen
@gen.coroutine
def fetch_coroutine(url):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(url)
# In Python versions prior to 3.3, returning a value from
# a generator is not allowed and you must use
# raise gen.Return(response.body)
# instead.
return response.body
~~~
### Python 3.5: `async` and `await`
Python 3.5 introduces the `async` and `await` keywords (functionsusing these keywords are also called “native coroutines”). Starting inTornado 4.3, you can use them in place of `yield`-based coroutines.Simply use `async def foo()` in place of a function definition withthe `@gen.coroutine` decorator, and `await` in place of yield. Therest of this document still uses the `yield` style for compatibilitywith older versions of Python, but `async` and `await` will runfaster when they are available:
~~~
async def fetch_coroutine(url):
http_client = AsyncHTTPClient()
response = await http_client.fetch(url)
return response.body
~~~
The `await` keyword is less versatile than the `yield` keyword.For example, in a `yield`-based coroutine you can yield a list of`Futures`, while in a native coroutine you must wrap the list in[`tornado.gen.multi`](# "tornado.gen.multi"). You can also use [`tornado.gen.convert_yielded`](# "tornado.gen.convert_yielded")to convert anything that would work with `yield` into a form thatwill work with `await`.
While native coroutines are not visibly tied to a particular framework(i.e. they do not use a decorator like [`tornado.gen.coroutine`](# "tornado.gen.coroutine") or[`asyncio.coroutine`](https://docs.python.org/3.4/library/asyncio-task.html#asyncio.coroutine "(in Python v3.4)") [https://docs.python.org/3.4/library/asyncio-task.html#asyncio.coroutine]), not all coroutines are compatible with eachother. There is a *coroutine runner* which is selected by the firstcoroutine to be called, and then shared by all coroutines which arecalled directly with `await`. The Tornado coroutine runner isdesigned to be versatile and accept awaitable objects from anyframework; other coroutine runners may be more limited (for example,the `asyncio` coroutine runner does not accept coroutines from otherframeworks). For this reason, it is recommended to use the Tornadocoroutine runner for any application which combines multipleframeworks. To call a coroutine using the Tornado runner from within acoroutine that is already using the asyncio runner, use the[`tornado.platform.asyncio.to_asyncio_future`](# "tornado.platform.asyncio.to_asyncio_future") adapter.
### How it works
A function containing `yield` is a **generator**. All generatorsare asynchronous; when called they return a generator object insteadof running to completion. The `@gen.coroutine` decoratorcommunicates with the generator via the `yield` expressions, andwith the coroutine's caller by returning a [`Future`](# "tornado.concurrent.Future").
Here is a simplified version of the coroutine decorator's inner loop:
~~~
# Simplified inner loop of tornado.gen.Runner
def run(self):
# send(x) makes the current yield return x.
# It returns when the next yield is reached
future = self.gen.send(self.next)
def callback(f):
self.next = f.result()
self.run()
future.add_done_callback(callback)
~~~
The decorator receives a [`Future`](# "tornado.concurrent.Future") from the generator, waits (withoutblocking) for that [`Future`](# "tornado.concurrent.Future") to complete, then “unwraps” the [`Future`](# "tornado.concurrent.Future")and sends the result back into the generator as the result of the`yield` expression. Most asynchronous code never touches the [`Future`](# "tornado.concurrent.Future")class directly except to immediately pass the [`Future`](# "tornado.concurrent.Future") returned byan asynchronous function to a `yield` expression.
### How to call a coroutine
Coroutines do not raise exceptions in the normal way: any exceptionthey raise will be trapped in the [`Future`](# "tornado.concurrent.Future") until it is yielded. Thismeans it is important to call coroutines in the right way, or you mayhave errors that go unnoticed:
~~~
@gen.coroutine
def divide(x, y):
return x / y
def bad_call():
# This should raise a ZeroDivisionError, but it won't because
# the coroutine is called incorrectly.
divide(1, 0)
~~~
In nearly all cases, any function that calls a coroutine must be acoroutine itself, and use the `yield` keyword in the call. When youare overriding a method defined in a superclass, consult thedocumentation to see if coroutines are allowed (the documentationshould say that the method “may be a coroutine” or “may return a[`Future`](# "tornado.concurrent.Future")”):
~~~
@gen.coroutine
def good_call():
# yield will unwrap the Future returned by divide() and raise
# the exception.
yield divide(1, 0)
~~~
Sometimes you may want to “fire and forget” a coroutine without waitingfor its result. In this case it is recommended to use [`IOLoop.spawn_callback`](# "tornado.ioloop.IOLoop.spawn_callback"),which makes the [`IOLoop`](# "tornado.ioloop.IOLoop") responsible for the call. If it fails,the [`IOLoop`](# "tornado.ioloop.IOLoop") will log a stack trace:
~~~
# The IOLoop will catch the exception and print a stack trace in
# the logs. Note that this doesn't look like a normal call, since
# we pass the function object to be called by the IOLoop.
IOLoop.current().spawn_callback(divide, 1, 0)
~~~
Finally, at the top level of a program, *if the `.IOLoop` is not yetrunning,* you can start the [`IOLoop`](# "tornado.ioloop.IOLoop"), run the coroutine, and thenstop the [`IOLoop`](# "tornado.ioloop.IOLoop") with the [`IOLoop.run_sync`](# "tornado.ioloop.IOLoop.run_sync") method. This is oftenused to start the `main` function of a batch-oriented program:
~~~
# run_sync() doesn't take arguments, so we must wrap the
# call in a lambda.
IOLoop.current().run_sync(lambda: divide(1, 0))
~~~
### Coroutine patterns
### Interaction with callbacks
To interact with asynchronous code that uses callbacks instead of[`Future`](# "tornado.concurrent.Future"), wrap the call in a [`Task`](# "tornado.gen.Task"). This will add the callbackargument for you and return a [`Future`](# "tornado.concurrent.Future") which you can yield:
~~~
@gen.coroutine
def call_task():
# Note that there are no parens on some_function.
# This will be translated by Task into
# some_function(other_args, callback=callback)
yield gen.Task(some_function, other_args)
~~~
### Calling blocking functions
The simplest way to call a blocking function from a coroutine is touse a [`ThreadPoolExecutor`](https://docs.python.org/3.4/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor "(in Python v3.4)") [https://docs.python.org/3.4/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor], which returns`Futures` that are compatible with coroutines:
~~~
thread_pool = ThreadPoolExecutor(4)
@gen.coroutine
def call_blocking():
yield thread_pool.submit(blocking_func, args)
~~~
### Parallelism
The coroutine decorator recognizes lists and dicts whose values are`Futures`, and waits for all of those `Futures` in parallel:
~~~
@gen.coroutine
def parallel_fetch(url1, url2):
resp1, resp2 = yield [http_client.fetch(url1),
http_client.fetch(url2)]
@gen.coroutine
def parallel_fetch_many(urls):
responses = yield [http_client.fetch(url) for url in urls]
# responses is a list of HTTPResponses in the same order
@gen.coroutine
def parallel_fetch_dict(urls):
responses = yield {url: http_client.fetch(url)
for url in urls}
# responses is a dict {url: HTTPResponse}
~~~
### Interleaving
Sometimes it is useful to save a [`Future`](# "tornado.concurrent.Future") instead of yielding itimmediately, so you can start another operation before waiting:
~~~
@gen.coroutine
def get(self):
fetch_future = self.fetch_next_chunk()
while True:
chunk = yield fetch_future
if chunk is None: break
self.write(chunk)
fetch_future = self.fetch_next_chunk()
yield self.flush()
~~~
### Looping
Looping is tricky with coroutines since there is no way in Pythonto `yield` on every iteration of a `for` or `while` loop andcapture the result of the yield. Instead, you'll need to separatethe loop condition from accessing the results, as in this examplefrom [Motor](http://motor.readthedocs.org/en/stable/) [http://motor.readthedocs.org/en/stable/]:
~~~
import motor
db = motor.MotorClient().test
@gen.coroutine
def loop_example(collection):
cursor = db.collection.find()
while (yield cursor.fetch_next):
doc = cursor.next_object()
~~~
### Running in the background
[`PeriodicCallback`](# "tornado.ioloop.PeriodicCallback") is not normally used with coroutines. Instead, acoroutine can contain a `while True:` loop and use[`tornado.gen.sleep`](# "tornado.gen.sleep"):
~~~
@gen.coroutine
def minute_loop():
while True:
yield do_something()
yield gen.sleep(60)
# Coroutines that loop forever are generally started with
# spawn_callback().
IOLoop.current().spawn_callback(minute_loop)
~~~
Sometimes a more complicated loop may be desirable. For example, theprevious loop runs every `60+N` seconds, where `N` is the runningtime of `do_something()`. To run exactly every 60 seconds, use theinterleaving pattern from above:
~~~
@gen.coroutine
def minute_loop2():
while True:
nxt = gen.sleep(60) # Start the clock.
yield do_something() # Run while the clock is ticking.
yield nxt # Wait for the timer to run out.
~~~
© Copyright 2009-2016, The Tornado Authors. Created using [Sphinx](http://sphinx-doc.org/) 1.3.5.
- User's guide
- Introduction
- Asynchronous and non-Blocking I/O
- Coroutines
- Queue example - a concurrent web spider
- Structure of a Tornado web application
- Templates and UI
- Authentication and security
- Running and deploying
- Web framework
- tornado.web — RequestHandler and Application classes
- tornado.template — Flexible output generation
- tornado.escape — Escaping and string manipulation
- tornado.locale — Internationalization support
- tornado.websocket — Bidirectional communication to the browser
- HTTP servers and clients
- tornado.httpserver — Non-blocking HTTP server
- tornado.httpclient — Asynchronous HTTP client
- tornado.httputil — Manipulate HTTP headers and URLs
- tornado.http1connection – HTTP/1.x client/server implementation
- Asynchronous networking
- tornado.ioloop — Main event loop
- tornado.iostream — Convenient wrappers for non-blocking sockets
- tornado.netutil — Miscellaneous network utilities
- tornado.tcpclient — IOStream connection factory
- tornado.tcpserver — Basic IOStream-based TCP server
- Coroutines and concurrency
- tornado.gen — Simplify asynchronous code
- tornado.concurrent — Work with threads and futures
- tornado.locks – Synchronization primitives
- tornado.queues – Queues for coroutines
- tornado.process — Utilities for multiple processes
- Integration with other services
- tornado.auth — Third-party login with OpenID and OAuth
- tornado.wsgi — Interoperability with other Python frameworks and servers
- tornado.platform.asyncio — Bridge between asyncio and Tornado
- tornado.platform.caresresolver — Asynchronous DNS Resolver using C-Ares
- tornado.platform.twisted — Bridges between Twisted and Tornado
- Utilities
- tornado.autoreload — Automatically detect code changes in development
- tornado.log — Logging support
- tornado.options — Command-line parsing
- tornado.stack_context — Exception handling across asynchronous callbacks
- tornado.testing — Unit testing support for asynchronous code
- tornado.util — General-purpose utilities
- Frequently Asked Questions
- Release notes
- What's new in Tornado 4.3
- What's new in Tornado 4.2.1
- What's new in Tornado 4.2
- What's new in Tornado 4.1
- What's new in Tornado 4.0.2
- What's new in Tornado 4.0.1
- What's new in Tornado 4.0
- What's new in Tornado 3.2.2
- What's new in Tornado 3.2.1
- What's new in Tornado 3.2
- What's new in Tornado 3.1.1
- What's new in Tornado 3.1
- What's new in Tornado 3.0.2
- What's new in Tornado 3.0.1
- What's new in Tornado 3.0
- What's new in Tornado 2.4.1
- What's new in Tornado 2.4
- What's new in Tornado 2.3
- What's new in Tornado 2.2.1
- What's new in Tornado 2.2
- What's new in Tornado 2.1.1
- What's new in Tornado 2.1
- What's new in Tornado 2.0
- What's new in Tornado 1.2.1
- What's new in Tornado 1.2
- What's new in Tornado 1.1.1
- What's new in Tornado 1.1
- What's new in Tornado 1.0.1
- What's new in Tornado 1.0