2017-11-08 16 views
3

간단한 예제 : 두 개의 관련없는 HTTP 요청을 병렬로 만들어야합니다. 가장 간단한 방법은 무엇입니까? 나는 그것이 그렇게 될 것으로 기대 :파이썬의 코 루틴에서 병렬 비동기 IO

async def do_the_job(): 
    with aiohttp.ClientSession() as session: 
     coro_1 = session.get('http://httpbin.org/get') 
     coro_2 = session.get('http://httpbin.org/ip') 
     return combine_responses(await coro_1, await coro_2) 

즉, 내가 IO 작업을 시작하고 효과적으로 병렬로 실행할 수 있도록 그 결과를 기다려야합니다. 이것은 asyncio.gather을 달성 할 수 있습니다

async def do_the_job(): 
    with aiohttp.ClientSession() as session: 
     coro_1 = session.get('http://example.com/get') 
     coro_2 = session.get('http://example.org/tp') 
     return combine_responses(*(await asyncio.gather(coro_1, coro_2))) 

다음, 좀 복잡한 의존성 구조를 갖고 싶어? 결과를 얻으 려 할 때 결과를 얻고 싶습니다. 여기에 별도 이벤트 루프에 의해 관리되는 코 루틴에서 별도의 작업을하게 asyncio.ensure_future하는 데 도움이 :

async def do_the_job(): 
    with aiohttp.ClientSession() as session: 
     fut_1 = asyncio.ensure_future(session.get('http://httpbin.org/ip')) 
     coro_2 = session.get('http://httpbin.org/get') 
     coro_3 = session.post('http://httpbin.org/post', data=(await coro_2) 
     coro_3_result = await coro_3 
     return combine_responses(await fut_1, coro_3_result) 

이 사실 병렬 내 논리 흐름에서 코 루틴과 IO 비 차단 달성하기 위해, 즉, 내가 사용해야 하나 asyncio.ensure_future 또는 asyncio.gather (실제로는 asyncio.ensure_future)? 덜 "장황한"방법이 있습니까?

일반적으로 개발자는 coroutines가 별도의 작업이되어야한다고 생각하고 최적의 성능을 얻기 위해 앞서 언급 한 기능을 사용해야합니까?

이벤트 루프에서 여러 작업을 수행하지 않고 동시 루틴을 사용할 수 있습니까?

실제 상황에서 이벤트 루프 작업이 얼마나 무겁습니까? 확실히 OS 쓰레드 나 프로세스보다 "가볍다". 그러한 작업의 가능한 최소 수를 위해 어느 정도까지 노력해야합니까?

답변

5

두 개의 관련없는 HTTP 요청을 병렬로 만들어야합니다. 가장 간단한 방법은 입니다.

import asyncio 
import aiohttp 


async def request(url): 
    async with aiohttp.ClientSession() as session: 
     async with session.get(url) as resp: 
      return await resp.text() 


async def main(): 
    results = await asyncio.gather(
     request('http://httpbin.org/delay/1'), 
     request('http://httpbin.org/delay/1'), 
    ) 
    print(len(results)) 


loop = asyncio.get_event_loop() 
try: 
    loop.run_until_complete(main()) 
    loop.run_until_complete(loop.shutdown_asyncgens()) 
finally: 
    loop.close() 

예, asyncio.gather 또는 asyncio.ensure_future와 함께 작업을 만드는 동시성을 달성 할 수있다.

다음으로 몇 가지 복잡한 종속 구조가 필요합니까? 결과를 얻으 려 할 때 작업을 시작하고 그 전제 조건을 모두 가지고 결과를 얻고 싶습니다.

귀하가 제공 한 코드가 일을 할 것입니다하지만, 다른 코 루틴에 동시 흐름을 분리하고 다시 asyncio.gather 사용하는 것이 좋을 것입니다 :

import asyncio 
import aiohttp 


async def request(url): 
    async with aiohttp.ClientSession() as session: 
     async with session.get(url) as resp: 
      return await resp.text() 


async def get_ip(): 
    return await request('http://httpbin.org/ip') 


async def post_from_get(): 
    async with aiohttp.ClientSession() as session: 
     async with session.get('http://httpbin.org/get') as resp: 
      get_res = await resp.text() 
     async with session.post('http://httpbin.org/post', data=get_res) as resp: 
      return await resp.text() 


async def main(): 
    results = await asyncio.gather(
     get_ip(), 
     post_from_get(), 
    ) 
    print(len(results)) 


loop = asyncio.get_event_loop() 
try: 
    loop.run_until_complete(main()) 
    loop.run_until_complete(loop.shutdown_asyncgens()) 
finally: 
    loop.close() 

일반적으로 개발자가 어떤 코 루틴을 생각해야 그것이 사실인가요 은 별도의 작업이되어야하며 위의 기능을 사용하여 최적의 성능을 얻으실 수 있습니까?

asyncio를 사용 했으므로 일부 작업을 동시에 실행하여 성능을 얻으시겠습니까? asyncio.gather은 "결과를 빠르게 얻기 위해이 작업들을 동시에 실행하십시오"라고 말할 수있는 방법입니다.

성능을 얻기 위해 어떤 작업을 동시에 실행해야하는지 생각할 필요가없는 경우 일반 동기화 코드로 확인하실 수 있습니다.

이벤트 루프에서 여러 작업없이 코 루틴을 사용하여 한 지점이 있습니까?

코드에서 원하지 않는 작업을 수동으로 만들지 않아도됩니다.이 대답의 코드 단편은 asyncio.ensure_future을 사용하지 않습니다. 그러나 내부적으로 asyncio은 작업을 계속 사용합니다 (예 : asyncio.gather은 작업 자체를 사용함).

실제 상황에서 이벤트 루프 작업이 얼마나 과중합니까? 확실히 그들은 OS 스레드 또는 프로세스보다 "가벼운" 입니다. 그러한 작업의 가능한 최소 수를 위해 어느 정도까지 을 노력해야합니까?

비동기 프로그램의 주요 병목 현상은 (거의 항상) 네트워크입니다. asyncio coroutines/tasks의 수는 전혀 걱정할 필요가 없습니다.

+0

주로 내 질문에 대한 답변입니다. 'asyncio.gather'와 코 루틴 함수 또는'asyncio.ensure_future'를 사용한 연결은 코 루틴과 병렬로 IO를 수행하는 표준 방법입니다. 요점으로, 필자는 예제 코드가 잘못해서 aiohttp를 사용한다는 것을 이해했다. –