2017-10-28 2 views
1

docs는 ClientSession을 다시 사용한다고 말합니다.aiohttp ClientSession 풀을 다시 사용하는 방법은 무엇입니까?

요청 당 세션을 만들지 마십시오. 모든 요청을 모두 수행하는 응용 프로그램 당 세션이 필요할 가능성이 큽니다.

세션에 연결 풀이 포함되어 있고 연결 재사용 및 연결 유지 (둘 다 기본적으로 설정되어 있음)로 인해 총 성능이 향상 될 수 있습니다. 1

그러나이 작업을 수행하는 방법에 대한 문서에는 아무런 설명이없는 것 같습니다. 어쩌면 관련성이있는 한 가지 예가 있지만 다른 곳에서 풀을 재사용하는 방법을 보여주지는 못합니다 : http://aiohttp.readthedocs.io/en/stable/client.html#keep-alive-connection-pooling-and-cookie-sharing

이렇게하는 것이 올바른 방법일까요?

1)

인스턴스 ClientSession의 한 세션 객체입니다

@app.listener('before_server_start') 
async def before_server_start(app, loop): 
    app.pg_pool = await asyncpg.create_pool(**DB_CONFIG, loop=loop, max_size=100) 
    app.http_session_pool = aiohttp.ClientSession() 


@app.listener('after_server_stop') 
async def after_server_stop(app, loop): 
    app.http_session_pool.close() 
    app.pg_pool.close() 


@app.post("/api/register") 
async def register(request): 
    # json validation 
    async with app.pg_pool.acquire() as pg: 
     await pg.execute() # create unactivated user in db 
     async with app.http_session_pool as session: 
      # TODO send activation email using SES API 
      async with session.post('http://httpbin.org/post', data=b'data') as resp: 
       print(resp.status) 
       print(await resp.text()) 
     return HTTPResponse(status=204) 

답변

1

내가 개선 될 수 있다고 생각 몇 가지있어. 이 세션에는 연결 풀이 포함되어 있지만 "session_pool"자체는 아닙니다. http_session_poolhttp_session으로 바꾸거나 client_session 일 수 있습니다.

2)

세션의 close()is a corountine 방법. 여러분을 기다리고해야합니다

await app.client_session.close() 

또는 더 나은 (IMHO)를 대신 생각의 방법 __aenter__/__aexit__의 대기와 제대로 열기/닫기 세션 사용 표준 비동기 컨텍스트 매니저 :

@app.listener('before_server_start') 
async def before_server_start(app, loop): 
    # ... 
    app.client_session = await aiohttp.ClientSession().__aenter__() 


@app.listener('after_server_stop') 
async def after_server_stop(app, loop): 
    await app.client_session.__aexit__(None, None, None) 
    # ... 

3)

에주의 this info에 :

그러나 기본 연결 이 닫히기 전에 이벤트 루프가 중지 된 경우 ResourceWarning: unclosed transport 경고가 발생합니다 (경고가 활성화 된 경우) .

이러한 상황을 피하려면 열려있는 모든 기본 연결을 닫을 수 있도록 이벤트 루프를 닫기 전에 약간의 지연을 추가해야합니다.

나는 귀하의 경우 필수입니다 모르겠지만 나쁜 아무것도 문서 조언으로 after_server_stop 내부 await asyncio.sleep(0)을 추가하는 없다 :

@app.listener('after_server_stop') 
async def after_server_stop(app, loop): 
    # ... 
    await asyncio.sleep(0) # http://aiohttp.readthedocs.io/en/stable/client.html#graceful-shutdown 

UPD :

클래스 __aenter__/__aexit__를 구현 async context manager으로 사용할 수 있습니다 (async with 문에 사용할 수 있음). 내부 블록을 실행하기 전에 몇 가지 조치를 취할 수 있습니다. 이는 일반 컨텍스트 관리자와 매우 유사하지만 asyncio과 관련됩니다. 일반 컨텍스트 관리자와 마찬가지로 async는 __aenter__/__aexit__을 수동으로 기다리는 async with없이 직접 사용할 수 있습니다.

close() 대신 __aenter__/__aexit__을 수동으로 사용하는 것이/무료 세션을 만드는 것이 더 좋은 이유는 무엇입니까? 우리가 실제로 무슨 일이 일어나는지 걱정해서는 안되기 때문에 __aenter__/__aexit__. 예를 들어 open()을 기다릴 필요가있을 때 세션을 생성하는 aiohttp의 향후 버전을 상상해보십시오. __aenter__/__aexit__을 사용하면 코드를 어떻게 든 변경하지 않아도됩니다.

+0

3)에 추가하기 만하면 SSL (https?)을 사용하는 경우 0.25 초가 사용됩니다. 또한 물어보기가 싫지만 다른 곳에서 '__aenter__/__aexit__'에 대한 설명을 찾지 못했습니다 ... 어떻게 다른지 설명해 주시겠습니까? (그들은 단지 @ asyncio.coroutine 데코레이터가있는 포장지처럼 보입니다.) – dtgq

+1

@dtgq'__aenter__' /'__aexit__'에 대한 정보를 추가하여 답변을 업데이트했습니다. 0.25 초가되면 - 예, https URL을 요청할 수 있다고 생각한다면 이해가됩니다. –

관련 문제