In Tornado, we usually write the following code to call a function asynchronously:
class MainHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def post(self): ... yield self.handleRequest(foo) ... @tornado.gen.coroutine def handleRequest(self, foo): ...
But in asyncio (will be shipped with Python 3.4, can be installed from pip for Python 3.3), we use yield from
to achieve the same thing:
@asyncio.coroutine def myPostHandler(): ... yield from handleRequest(foo) ... @asyncio.coroutine def handleRequest(foo) ...
Seeing from the code, the difference is yield
and yield from
. However the former handleRequest(foo)
returns a tornado.concurrent.Future
object, the latter returns a generator
object.
My question is, what is the difference between the two things in mechanism? How is the control flow? And who calls the actual handleRequest
and retrieves its returning value?
Append: I have basic knowledge of Python generators and iterators. I wanted to understand what Tornado and asyncio achieved by using these, and what is the difference between those two mechanisms.
There is a huge difference between the two. yield from
takes another generator and continues yielding from that generator instead (delegating responsibility, as it were). yield
just yields one value.
In other words, yield from
, in the simplest case, could be replaced by:
for value in self.handleRequest(foo): yield value
If you replaced a yield from <expression>
line with yield <expression>
you'd return the whole generator to the caller, not the values that generator produces.
The yield from
syntax was only introduced in Python 3.3, see PEP 380: Syntax for Delegating to a Subgenerator. Tornado supports Python versions 2.6, 2.7 and 3.2 in addition to Python 3.3, so it cannot rely on the yield from
syntax being available. asyncio
, on the other hand, being a core Python library added in 3.4, can fully rely on the yield from
generator delegation syntax being available.
As a result, Tornado will have to post-process values yielded from a @tornado.gen.coroutine
generator to detect that a tornado.concurrent.Future
object was yielded; the @asyncio.coroutine
code handling can be much simpler. And indeed the Tornado Runner.run()
method does explicit type checks to handle delegated tasks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With