Ильдар
Quiero usar el rendimiento del generador y las funciones asíncronas. Leí este tema y escribí el siguiente código:
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
Pero tengo el error:
SyntaxError: ‘rendimiento’ dentro de la función asíncrona
¿Cómo usar el generador de rendimiento en la función asíncrona?
Mijaíl Gerasimov
Actualización:
Comenzando con Python 3.6 tenemos generadores asincrónicos y capaz de usar yield
directamente dentro de 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.loop.shutdown_asyncgens
loop.close()
Respuesta anterior para Python 3.5:
no puedes yield
corrutinas internas. La única manera es implementar Iterador asíncrono usando manualmente __aiter__
/__anext__
métodos mágicos. En tu caso:
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())
Producción:
0
1
4
Aquí hay dos ejemplos más: 1, 2
-
Basado en su código Python 3.6, hice un ejemplo para usar
matlibplot
por si a alguien le interesa: stackoverflow.com/questions/44163601/…– Numes Sanguis
25 de mayo de 2017 a las 8:14
El nuevo Python 3.6 viene con soporte para generadores asíncronos.
PD: En el momento de escribir, Python 3.6 aún es beta. Si está en GNU/Linux o OS X y no puede esperar, puede probar el nuevo Python con pyenv.
Esto debería funcionar con python 3.6 (probado con 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
¿Es eso posible? Parecen dos diseños opuestos. Los generadores están hechos para no producir valor a menos que sea necesario, lo que significa que, en principio, deben manejar tener un Expresar.
async
por otro lado sugeriría que la función llamada no puede depender de su estado. De lo contrario tendrás carreras de datos. Parece realmente engorroso admitir generadores asíncronos, tendrían que envolverse con mecanismos de bloqueo. Entonces, probablemente la respuesta a su pregunta esté en algún lugar en esta dirección.– luk32
31 mayo 2016 a las 15:39
¿Puedes devolver un objeto futuro y luego ceder ese objeto cuando quieras sus datos? Nunca he usado asyncio, pero así es como se hace con Tornado.
– raíz reticente
31 mayo 2016 a las 15:45
No creo que un generador asíncrono tenga ningún sentido. Debería poder devolver un generador desde una función asíncrona. ¿Hay algo que quieras lograr o solo estás probando cosas?
– sinónimo
31 de mayo de 2016 a las 15:56
¿Se puede usar Evento? createGenerator será un evento de configuración y el inicio será un evento de espera. escribí esta solución. Es trabajo, pero quiero más código agradable.
– Ильдар
31 de mayo de 2016 a las 16:03
@Ильдар, ¿viste la segunda respuesta? ¿Que piensas de eso? Parece que funciona.
– Mijaíl Gerasimov
2 de junio de 2016 a las 12:15