tutorial loop español await asyncio async python asynchronous async-await python-3.5 python-asyncio

loop - Python 3.5 async/await con ejemplo de código real



python async await (1)

He leído montones de artículos y tutoriales sobre el tema 3.5 async / await de Python. Debo decir que estoy bastante confundido, porque algunos usan get_event_loop () y run_until_complete (), algunos usan asegurar_future (), algunos usan asyncio.wait (), y otros usan call_soon ().

Parece que tengo muchas opciones, pero no tengo ni idea de si son completamente idénticas o hay casos en los que usas bucles y hay casos en los que usas wait ().

Pero la cosa es que todos los ejemplos funcionan con asyncio.sleep() como simulación de una operación realmente lenta que devuelve un objeto que se puede esperar. Una vez que trato de cambiar esta línea por un código real, todo falla. ¿Cuáles son las diferencias entre los enfoques escritos anteriormente y cómo debo ejecutar una biblioteca de terceros que no esté lista para async / await. Utilizo el servicio de Quandl para obtener algunos datos de stock.

import asyncio import quandl async def slow_operation(n): # await asyncio.sleep(1) # Works because it''s await ready. await quandl.Dataset(n) # Doesn''t work because it''s not await ready. async def main(): await asyncio.wait([ slow_operation("SIX/US9884981013EUR4"), slow_operation("SIX/US88160R1014EUR4"), ]) # You don''t have to use any code for 50 requests/day. quandl.ApiConfig.api_key = "MY_SECRET_CODE" loop = asyncio.get_event_loop() loop.run_until_complete(main())

Espero que entiendas lo perdido que me siento y lo simple que me gustaría tener corriendo en paralelo.


Si una biblioteca de terceros no es compatible con async/await , obviamente no puede usarla fácilmente. Hay dos casos:

  1. Digamos que la función en la biblioteca es asíncrona y le da una devolución de llamada, por ejemplo,

    def fn(..., clb): ...

    Así que puedes hacer:

    def on_result(...): ... fn(..., on_result)

    En ese caso, puede incluir tales funciones en el protocolo asyncio como este:

    from asyncio import Future def wrapper(...): future = Future() def my_clb(...): future.set_result(xyz) fn(..., my_clb) return future

    (use future.set_exception(exc) en la excepción)

    Luego, simplemente puede llamar a ese contenedor en alguna función async con await :

    value = await wrapper(...)

    Tenga en cuenta que await trabajos con cualquier objeto Future . No tienes que declarar wrapper como async .

  2. Si la función en la biblioteca es síncrona, entonces puede ejecutarla en un subproceso separado (probablemente usaría un grupo de subprocesos para eso). El código completo puede verse así:

    import asyncio import time from concurrent.futures import ThreadPoolExecutor # Initialize 10 threads THREAD_POOL = ThreadPoolExecutor(10) def synchronous_handler(param1, ...): # Do something synchronous time.sleep(2) return "foo" # Somewhere else async def main(): loop = asyncio.get_event_loop() futures = [ loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...), ] await asyncio.wait(futures) for future in futures: print(future.result()) with THREAD_POOL: loop = asyncio.get_event_loop() loop.run_until_complete(main())

Si no puede usar los hilos por cualquier motivo, el uso de dicha biblioteca simplemente hace que el código asíncrono no tenga sentido.

Sin embargo, tenga en cuenta que usar una biblioteca sincrónica con async es probablemente una mala idea. No obtendrás mucho y, sin embargo, complicas mucho el código.