Doc rework to use the async/await syntax.

This commit is contained in:
Nicolas Di Pietro
2016-07-10 15:42:15 +02:00
parent b35eabd9bc
commit 4cd97d47df
3 changed files with 35 additions and 47 deletions

View File

@@ -272,7 +272,7 @@ Have a look at the highlighted lines - here is what we do:
.. note:: .. note::
The reason ``returnValue`` is necessary goes deep into implementation details of Twisted and Python. In short: co-routines in Python 2 with Twisted are simulated using exceptions. Only Python 3.3+ has gotten native support for co-routines using the new yield from statement. The reason ``returnValue`` is necessary goes deep into implementation details of Twisted and Python. In short: co-routines in Python 2 with Twisted are simulated using exceptions. Only Python 3.3+ has gotten native support for co-routines using the new yield from statement, Python 3.5+ use await statement and it is the new recommended method.
In above, we are using a little helper :func:`autobahn.twisted.util.sleep` for sleeping "inline". The helper is really trivial: In above, we are using a little helper :func:`autobahn.twisted.util.sleep` for sleeping "inline". The helper is really trivial:
@@ -298,7 +298,7 @@ Asyncio Futures and Coroutines
On the other hand, asyncio futures are quite different from Twisted Deferreds. One difference is that they have no built-in machinery for chaining. On the other hand, asyncio futures are quite different from Twisted Deferreds. One difference is that they have no built-in machinery for chaining.
`Asyncio Coroutines <http://docs.python.org/3.4/library/asyncio-task.html#coroutines>`__ are (on a certain level) quite similar to Twisted inline callbacks. Here is the code corresponding to our example above: `Asyncio Coroutines <http://docs.python.org/3.5/library/asyncio-task.html#coroutines>`__ are (on a certain level) quite similar to Twisted inline callbacks. Here is the code corresponding to our example above:
------- -------
@@ -355,19 +355,17 @@ Now, when converted to ``asyncio.coroutine``, the code becomes:
.. code-block:: python .. code-block:: python
:linenos: :linenos:
:emphasize-lines: 3,5,6 :emphasize-lines: 3,4,5
import asyncio import asyncio
@asyncio.coroutine async def slow_square(x):
def slow_square(x): await asyncio.sleep(1)
yield from asyncio.sleep(1)
return x * x return x * x
@asyncio.coroutine async def test():
def test(): res = await slow_square(3)
res = yield from slow_square(3)
print(res) print(res)
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
@@ -375,9 +373,9 @@ Now, when converted to ``asyncio.coroutine``, the code becomes:
The main differences (on surface) are: The main differences (on surface) are:
1. The use of the decorator ``@asyncio.coroutine`` (line 3) in asyncio versus ``@defer.inlineCallbacks`` with Twisted 1. The declaration of the function with ``async`` keyword (line 3) in asyncio versus the decorator ``@defer.inlineCallbacks`` with Twisted
2. The use of ``defer.returnValue`` in Twisted for returning values whereas in asyncio, you can use plain returns (line 6) 2. The use of ``defer.returnValue`` in Twisted for returning values whereas in asyncio, you can use plain returns (line 6)
3. The use of ``yield from`` in asyncio, versus plain ``yield`` in Twisted (line 5) 3. The use of ``await`` in asyncio, versus ``yield`` in Twisted (line 5)
4. The auxiliary code to get the event loop started and stopped 4. The auxiliary code to get the event loop started and stopped
Most of the examples that follow will show code for both Twisted and asyncio, unless the conversion is trivial. Most of the examples that follow will show code for both Twisted and asyncio, unless the conversion is trivial.

View File

@@ -144,18 +144,16 @@ Here are quick templates for you to copy/paste for creating and running a WAMP c
**asyncio**: **asyncio**:
.. code-block:: python .. code-block:: python
:emphasize-lines: 2 :emphasize-lines: 1
from asyncio import coroutine
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
class MyComponent(ApplicationSession): class MyComponent(ApplicationSession):
@coroutine async def onJoin(self, details):
def onJoin(self, details):
print("session joined") print("session joined")
# can do subscribes, registers here e.g.: # can do subscribes, registers here e.g.:
# yield from self.subscribe(...) # await self.subscribe(...)
# yield from self.register(...) # await self.register(...)
if __name__ == '__main__': if __name__ == '__main__':
runner = ApplicationRunner(url=u"ws://localhost:8080/ws", realm=u"realm1") runner = ApplicationRunner(url=u"ws://localhost:8080/ws", realm=u"realm1")
@@ -248,21 +246,19 @@ Using **asyncio**, the example looks like this:
.. code-block:: python .. code-block:: python
:linenos: :linenos:
:emphasize-lines: 13 :emphasize-lines: 11
from autobahn.asyncio.wamp import ApplicationSession from autobahn.asyncio.wamp import ApplicationSession
from asyncio import coroutine
class MyComponent(ApplicationSession): class MyComponent(ApplicationSession):
@coroutine async def onJoin(self, details):
def onJoin(self, details):
print("session ready") print("session ready")
def add2(x, y): def add2(x, y):
return x + y return x + y
try: try:
yield from self.register(add2, u'com.myapp.add2') await self.register(add2, u'com.myapp.add2')
print("procedure registered") print("procedure registered")
except Exception as e: except Exception as e:
print("could not register procedure: {0}".format(e)) print("could not register procedure: {0}".format(e))
@@ -270,8 +266,8 @@ Using **asyncio**, the example looks like this:
The differences compared with the Twisted variant are: The differences compared with the Twisted variant are:
* the ``import`` of ``ApplicationSession`` * the ``import`` of ``ApplicationSession``
* the use of ``@coroutine`` to decorate co-routines * the use of ``async`` keyword to declare co-routines
* the use of ``yield from`` instead of ``yield`` * the use of ``await`` instead of ``yield``
.. _calling-procedures: .. _calling-procedures:
@@ -306,19 +302,17 @@ And here is the same done on **asyncio**
.. code-block:: python .. code-block:: python
:linenos: :linenos:
:emphasize-lines: 11 :emphasize-lines: 9
from autobahn.asyncio.wamp import ApplicationSession from autobahn.asyncio.wamp import ApplicationSession
from asyncio import coroutine
class MyComponent(ApplicationSession): class MyComponent(ApplicationSession):
@coroutine async def onJoin(self, details):
def onJoin(self, details):
print("session ready") print("session ready")
try: try:
res = yield from self.call(u'com.myapp.add2', 2, 3) res = await self.call(u'com.myapp.add2', 2, 3)
print("call result: {}".format(res)) print("call result: {}".format(res))
except Exception as e: except Exception as e:
print("call error: {0}".format(e)) print("call error: {0}".format(e))
@@ -383,22 +377,20 @@ The corresponding **asyncio** code looks like this
.. code-block:: python .. code-block:: python
:linenos: :linenos:
:emphasize-lines: 14 :emphasize-lines: 12
from autobahn.asyncio.wamp import ApplicationSession from autobahn.asyncio.wamp import ApplicationSession
from asyncio import coroutine
class MyComponent(ApplicationSession): class MyComponent(ApplicationSession):
@coroutine async def onJoin(self, details):
def onJoin(self, details):
print("session ready") print("session ready")
def oncounter(count): def oncounter(count):
print("event received: {0}", count) print("event received: {0}", count)
try: try:
yield from self.subscribe(oncounter, u'com.myapp.oncounter') await self.subscribe(oncounter, u'com.myapp.oncounter')
print("subscribed to topic") print("subscribed to topic")
except Exception as e: except Exception as e:
print("could not subscribe to topic: {0}".format(e)) print("could not subscribe to topic: {0}".format(e))
@@ -441,23 +433,21 @@ The corresponding **asyncio** code looks like this
.. code-block:: python .. code-block:: python
:linenos: :linenos:
:emphasize-lines: 13 :emphasize-lines: 11
from autobahn.asyncio.wamp import ApplicationSession from autobahn.asyncio.wamp import ApplicationSession
from asyncio import sleep from asyncio import sleep
from asyncio import coroutine
class MyComponent(ApplicationSession): class MyComponent(ApplicationSession):
@coroutine async def onJoin(self, details):
def onJoin(self, details):
print("session ready") print("session ready")
counter = 0 counter = 0
while True: while True:
self.publish(u'com.myapp.oncounter', counter) self.publish(u'com.myapp.oncounter', counter)
counter += 1 counter += 1
yield from sleep(1) await sleep(1)
.. tip:: .. tip::

View File

@@ -15,7 +15,7 @@ For example, here is how you call a remote procedure that takes no arguments and
print(now) print(now)
This is using `yield`, which assumes the context in that you run this code is a *co-routine* (something decorated with `defer.inlineDeferred` in Twisted or `asyncio.coroutine` in asyncio). This is using `yield`, which assumes the context in that you run this code is a *co-routine* (something decorated with `defer.inlineDeferred` in Twisted or declared with `async def` in asyncio).
The same call using plain Twisted Deferreds would look like: The same call using plain Twisted Deferreds would look like:
@@ -183,7 +183,7 @@ The direct asyncio equivalent of above would be:
import functools import functools
def print_sales(product, future): async def print_sales(product, future):
sales = future.result() sales = future.result()
print("Sales {}: {}".format(product, sales)) print("Sales {}: {}".format(product, sales))
@@ -192,7 +192,7 @@ The direct asyncio equivalent of above would be:
f = session.call("com.myapp.sales_by_product", product) f = session.call("com.myapp.sales_by_product", product)
f.add_done_callback(functools.partial(print_sales, product)) f.add_done_callback(functools.partial(print_sales, product))
fl.append(f) fl.append(f)
yield from asyncio.gather(*fl) await asyncio.gather(*fl)
> Note: Part of the verbosity stems from the fact that, different from Twisted's `addCallback`, asyncio's `add_done_callback` sadly does not take and forward `args` and `kwargs` to the callback added. > Note: Part of the verbosity stems from the fact that, different from Twisted's `addCallback`, asyncio's `add_done_callback` sadly does not take and forward `args` and `kwargs` to the callback added.
> >
@@ -201,12 +201,12 @@ However, there is a better way, if we restructure the code a litte:
.. code-block:: python .. code-block:: python
def get_and_print_sales(product): async def get_and_print_sales(product):
sales = yield from session.call("com.myapp.sales_by_product", product) sales = await session.call("com.myapp.sales_by_product", product)
print("Sales {}: {}".format(product, sales)) print("Sales {}: {}".format(product, sales))
tasks = [get_and_print_sales(product) for product in ["product2", "product3", "product5"]] tasks = [get_and_print_sales(product) for product in ["product2", "product3", "product5"]]
yield from asyncio.wait(tasks) await asyncio.wait(tasks)
Calls with complex results Calls with complex results
.......................... ..........................
@@ -248,7 +248,7 @@ Using asyncio coroutines (`asyncio.coroutine`):
.. code-block:: python .. code-block:: python
try: try:
res = yield from session.call("com.calculator.sqrt", -1) res = await session.call("com.calculator.sqrt", -1)
except ApplicationError as err: except ApplicationError as err:
print("Error: {}".format(err)) print("Error: {}".format(err))
else: else:
@@ -480,7 +480,7 @@ In asyncio, use
.. code-block:: python .. code-block:: python
registrations = yield from asyncio.gather(*session.register(calc)) registrations = await asyncio.gather(*session.register(calc))
to yield a list of registrations. to yield a list of registrations.