Problem with coroutines old-style / new-style usage and features

Ian Kelly ian.g.kelly at gmail.com
Thu Feb 1 14:19:59 EST 2018


On Thu, Feb 1, 2018 at 5:38 AM, Yahya Abou 'Imran via Python-list
<python-list at python.org> wrote:
> Hi guys.
>
> I am discovering coroutines and asynchronous programming, and I have a little problem with a little example I'm coding myself as an excercice.
>
> Let say you take two guys in the street: Dave and Bryan.
> You ask dave to count from 1 to 50, 1 by 1. He will do it fast.
> And you ask Bryan to count from 208 to 166 in reversing order, 7 by 7! It will take him some time between each number to think about it.
>
> Now I have a recorder wich is able to recognize voices. I use it to record both of them counting at the same time.
>
> Here is the recorder:
>
>
> @asyncio.coroutine
> def recorder():
>     dialog = []
>     while True:
>         sent = yield dialog
>         if sent is not None:
>             name, things = sent
>             dialog.append(f'{name} says : {things}')

This is not an asyncio coroutine. This is just a normal generator that
you're sending to. So you should probably remove the decorator to
prevent confusion. For that matter I'm not really sure why this isn't
just a class with synchronous "add" and "get" methods.

> It is storing the dialog, and you can ask him fot it later by sending None to it.
>
> For the calculation, I'm using a ascyn generator:
>
>
> async def calcul_mental(range_args, name, timeout=0.2):
>     for i in range(*range_args):
>         await asyncio.sleep(timeout)
>         yield name, i
>
>
> To link the two, I came up with this little coroutine:
>
>
> async def record(recorder, gen):
>     async for name, i in gen:
>         recorder.send([name, i])
>
>
> And my main:
>
>
> def main():
>
>     g1 = calcul_mental([1, 51],
>                        name='Dave',
>                        timeout=0.2)
>
>     g2 = calcul_mental([208, 165, -7],
>                        name='Bryan',
>                        timeout=2)
>
>     r = recorder()
>     r.send(None)
>
>     coros = asyncio.gather(record(r, g1), record(r, g2))
>     loop = asyncio.get_event_loop()
>     loop.run_until_complete(coros)
>
>     dialog = r.send(None)
>     for line in dialog:
>         print(line)
>
>
> It works well, but I was wondering if I could turn recorder into a new style coroutine...

Why? It doesn't do anything asynchronously.

> The problems are:
> - I can't await for an async generator;
> - I can't let an await alone to send data to it;
> - I can't turn it into an AsyncGenerator because it will lost the .send() method.
>
> I think it's just a problem of design, but I wasn't able to solve it myself.
>
> Any thoughts about it?

If it were a class, then you could make the individual methods be
coroutines if desired and await those.



More information about the Python-list mailing list