@asyncio.coroutine vs async def

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Post Reply
klauweg
Posts: 6
Joined: Fri Oct 11, 2019 3:29 pm

@asyncio.coroutine vs async def

Post by klauweg » Fri Oct 11, 2019 3:34 pm

Is there any practical difference between using the @asyncio.coroutine decorator and async keyword before def function?

User avatar
pythoncoder
Posts: 3607
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: @asyncio.coroutine vs async def

Post by pythoncoder » Sat Oct 12, 2019 7:35 am

No. However async def is the more modern syntax and is preferable in my opinion. I think it's best to adopt a consistent syntax.

CPython's asyncio went through various iterations leading to much confusion. There is a tutorial in this repo which promotes using the newest syntax for consistency. Programs written using those guidelines will be portable to CPython/asyncio except in the few clearly stated instances.
Peter Hinch

klauweg
Posts: 6
Joined: Fri Oct 11, 2019 3:29 pm

Re: @asyncio.coroutine vs async def

Post by klauweg » Sat Oct 12, 2019 9:27 am

Thank you Peter, for your quick reply.

Of course i've already found your helpful tutorial.

Nevertheless there are many questions. But that's not your fault. I'm quite new to python and this asyncio stuff in particular.

Hm, i've found this in uasyncio core:

Code: Select all

def coroutine(f):
return f
As far as i understand this decorator does exactly nothing?

By the way: where does the "async" keyword come from? Is this a language extension?

User avatar
jimmo
Posts: 648
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia

Re: @asyncio.coroutine vs async def

Post by jimmo » Sat Oct 12, 2019 1:18 pm

klauweg wrote:
Sat Oct 12, 2019 9:27 am
As far as i understand this decorator does exactly nothing?
There's a lot to unpack here... I'm not 100% I have this right but I think the overall answer is that the MicroPython implementation of async is quite closely aligned with the generator style of coroutines, whereas CPython has slightly different handling for "new style" async methods. So if you're writing an old-style co-routine (i.e. using yield), then the method will already be a generator (because it will contain yield statements) and will look exactly like an async method anyway. This is kind of an optimisation in MicroPython (which does lead to some small but mostly not noticeable differences to CPython). So this "do nothing" decorator just exists for compatibility with existing Python code that needs it to be there (because CPython does treat them differently internally).

To put it another way, in MicroPython, any generator (i.e. a method containing yields) already behaves like an async function, so the decorator does nothing.

You don't need to know this sort of stuff to use asyncio effectively. As Pete says, stick to the modern async/await syntax.
klauweg wrote:
Sat Oct 12, 2019 9:27 am
By the way: where does the "async" keyword come from? Is this a language extension?
It's a standard feature in Python since 3.5. See https://www.python.org/dev/peps/pep-049 ... ion-syntax which is the full story behind its addition to the language.

klauweg
Posts: 6
Joined: Fri Oct 11, 2019 3:29 pm

Re: @asyncio.coroutine vs async def

Post by klauweg » Sat Oct 12, 2019 4:52 pm

Thank you jimmo,
that makes something clear.

User avatar
pythoncoder
Posts: 3607
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: @asyncio.coroutine vs async def

Post by pythoncoder » Sun Oct 13, 2019 6:35 am

@klauweg As @jimmo says MicroPython makes no distinction between tasks (coroutines) and generators. In CPython they are entirely separate and any attempt to substitute one for the other will produce a syntax error. In the interests of code clarity (and CPython compatibility) I recommend treating the two as if they were different. This implies using async def and avoiding the use of yield in a task:

Code: Select all

import uasyncio as asyncio
async def foo():
    while True:
        # Do something
        await asyncio.sleep_ms(0)  # Not yield
In performance-critical code yield does offer a small advantage. There are other tricks such as yielding an integer (number of milliseconds to pause). In the great majority of cases code clarity trumps the small performance gain achieved by these hacks. In my opinion, of course.
Peter Hinch

Post Reply