66 votes

Comment utiliser 'yield' dans une fonction asynchrone ?

Je veux utiliser le générateur yield et les fonctions asynchrones. Je lis ce sujet et a écrit le code suivant :

import asyncio

async def createGenerator():
    mylist = range(3)
    for i in mylist:
        await asyncio.sleep(1)
        yield i*i

async def start():
    mygenerator = await createGenerator()
    for i in mygenerator:
        print(i)

loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(start())

except KeyboardInterrupt:
    loop.stop()
    pass

Mais j'ai eu l'erreur :

Erreur de syntaxe : 'yield' dans une fonction asynchrone

Comment utiliser le générateur de rendement dans une fonction asynchrone ?

92voto

germn Points 1316

Mise à jour :

En commençant par Python 3.6, nous avons générateurs asynchrones et capable d'utiliser yield directement dans les coroutines.

import asyncio

async def async_generator():
    for i in range(3):
        await asyncio.sleep(1)
        yield i*i

async def main():
    async for i in async_generator():
        print(i)

loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())  # see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.shutdown_asyncgens
    loop.close()

Ancienne réponse pour Python 3.5 :

Vous ne pouvez pas yield à l'intérieur des coroutines. Le seul moyen est d'implémenter Iterator asynchrone manuellement en utilisant __aiter__ / __anext__ des méthodes magiques. Dans votre cas :

import asyncio

class async_generator:
    def __init__(self, stop):
        self.i = 0
        self.stop = stop

    async def __aiter__(self):
        return self

    async def __anext__(self):
        i = self.i
        self.i += 1
        if self.i <= self.stop:
            await asyncio.sleep(1)
            return i * i
        else:
            raise StopAsyncIteration

async def main():
    async for i in async_generator(3):
        print(i)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Sortie :

0
1
4

Voici deux autres exemples : 1 , 2

8voto

rominf Points 127

Le nouveau Python 3.6 est doté d'un support pour les générateurs asynchrones.

PEP 0525

Nouveautés de Python 3.6

PS : Au moment d'écrire ces lignes, Python 3.6 est toujours en version bêta. Si vous êtes sous GNU/Linux ou OS X et que vous ne pouvez pas attendre vous pouvez essayer le nouveau Python avec pyenv .

4voto

Matus Points 266

Cela devrait fonctionner avec python 3.6 (testé avec 3.6.0b1) :

import asyncio

async def createGenerator():
    mylist = range(3)
    for i in mylist:
        await asyncio.sleep(1)
        yield i*i

async def start():
    async for i in createGenerator():
        print(i)

loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(start())

except KeyboardInterrupt:
    loop.stop()
    pass

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X