Estoy tratando de enseñarme a mí mismo la funcionalidad asíncrona de Python. Para ello he construido un raspador web asíncrono. Me gustaría limitar el número total de conexiones que tengo abiertas para ser un buen ciudadano en los servidores. Sé que los semáforos son una buena solución, y la biblioteca de asyncio tiene una clase de semáforos integrada. Mi problema es que Python se queja cuando usa el yield from
en una función async
cuando está combinando el yield
y la syntax. A continuación se muestra la syntax exacta que estoy usando …
import asyncio import aiohttp sema = asyncio.BoundedSemaphore(5) async def get_page_text(url): with (yield from sema): try: resp = await aiohttp.request('GET', url) if resp.status == 200: ret_val = await resp.text() except: raise ValueError finally: await resp.release() return ret_val
Elevando esta excepción:
File "", line 14 with (yield from sema): ^ SyntaxError: 'yield from' inside async function
Alguna posible solución que se me ocurra …
@asyncio.coroutine
Soy muy nuevo en la funcionalidad asíncrona de Python, por lo que podría faltar algo obvio.
Puede usar async with
sentencia para obtener un administrador de contexto asíncrono:
#!/usr/local/bin/python3.5 import asyncio from aiohttp import ClientSession sema = asyncio.BoundedSemaphore(5) async def hello(url): async with ClientSession() as session: async with sema, session.get(url) as response: response = await response.read() print(response) loop = asyncio.get_event_loop() loop.run_until_complete(hello("http://httpbin.org/headers"))
Ejemplo tomado de aquí . La página también es un buen manual para asyncio
y aiohttp
en general.
Bien, esto es realmente tonto, pero simplemente sustituyo el yield from
con await
en el administrador de contexto del semáforo y funciona perfectamente.
sema = asyncio.BoundedSemaphore(5) async def get_page_text(url): with (await sema): try: resp = await aiohttp.request('GET', url) if resp.status == 200: ret_val = await resp.text() except: raise ValueError finally: await resp.release() return ret_val