tutorial programming espaƱol asyncio async python python-3.x async-await python-asyncio aiohttp

programming - asyncio python tutorial



"Async con" en Python 3.4 (2)

Simplemente no use el resultado de session.get() como administrador de contexto; utilízalo como coroutine directamente en su lugar. El gestor de contexto de solicitud que session.get() produce normalmente liberaría la solicitud al salir, pero también lo hace usando response.text() , por lo que podría ignorarlo aquí:

@asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(10): response = yield from session.get(url) return (yield from response.text())

La envoltura de solicitud devuelta aquí no tiene los métodos asíncronos requeridos ( __aenter__ y __aexit__ ), se omiten por completo cuando no se usa Python 3.5 (consulte el código fuente correspondiente ).

Si tiene más declaraciones entre la llamada a session.get session.get() y el acceso al response.text() espera, probablemente desee try:..finally: todos modos para liberar la conexión; El administrador de contexto de la versión de Python 3.5 también cierra la respuesta si se produce una excepción. Debido a que se necesita un yield from response.release() aquí, esto no se puede encapsular en un administrador de contexto antes de Python 3.4:

import sys @asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(10): response = yield from session.get(url) try: # other statements return (yield from response.text()) finally: if sys.exc_info()[0] is not None: # on exceptions, close the connection altogether response.close() else: yield from response.release()

Los documentos de Inicio para aiohttp dan el siguiente ejemplo de cliente:

import asyncio import aiohttp async def fetch_page(session, url): with aiohttp.Timeout(10): async with session.get(url) as response: assert response.status == 200 return await response.read() loop = asyncio.get_event_loop() with aiohttp.ClientSession(loop=loop) as session: content = loop.run_until_complete( fetch_page(session, ''http://python.org'')) print(content)

Y dan la siguiente nota para los usuarios de Python 3.4:

Si está utilizando Python 3.4, reemplace aguardar con rendimiento de y async def con un decorador @coroutine.

Si sigo estas instrucciones obtengo:

import aiohttp import asyncio @asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(10): async with session.get(url) as response: return (yield from response.text()) if __name__ == ''__main__'': loop = asyncio.get_event_loop() with aiohttp.ClientSession(loop=loop) as session: html = loop.run_until_complete( fetch(session, ''http://python.org'')) print(html)

Sin embargo, esto no se ejecutará, ya que Python 3.4 no admite async with :

$ python3 client.py File "client.py", line 7 async with session.get(url) as response: ^ SyntaxError: invalid syntax

¿Cómo puedo traducir el async with declaración para trabajar con Python 3.4?


aiohttp examples aiohttp implementaron usando la sintaxis 3.4. Basado en el ejemplo del cliente json, su función sería:

@asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(10): resp = yield from session.get(url) try: return (yield from resp.text()) finally: yield from resp.release()

Actualizaciones:

Tenga en cuenta que la solución de Martijn funcionaría para casos simples, pero puede llevar a comportamientos no deseados en casos específicos:

@asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(5): response = yield from session.get(url) # Any actions that may lead to error: 1/0 return (yield from response.text()) # exception + warning "Unclosed response"

Además de la excepción, también obtendrá una advertencia "Respuesta sin cerrar". Esto puede dar lugar a fugas de conexiones en aplicaciones complejas. resp.release() este problema si llama manualmente resp.release() / resp.close() :

@asyncio.coroutine def fetch(session, url): with aiohttp.Timeout(5): resp = yield from session.get(url) try: # Any actions that may lead to error: 1/0 return (yield from resp.text()) except Exception as e: # .close() on exception. resp.close() raise e finally: # .release() otherwise to return connection into free connection pool. # It''s ok to release closed response: # https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/client_reqrep.py#L664 yield from resp.release() # exception only

Creo que es mejor seguir los ejemplos oficiales (y la implementation __aexit__ ) y llamar a resp.release() / resp.close() explícitamente.