Programming/Python

파이썬 코루틴(coroutine)

알로그 2022. 10. 2. 16:17
반응형

파이썬 코루틴(coroutine)

파이썬 비동기 함수는 코루틴 함수로 만들 수 있다.

코루틴은 진입점과 탈출점이 여러 개가 있는 함수라고 할 수 있다.

 

파이썬 코루틴 공식 홈페이지에 있는 예제를 살펴보면 asyncio API에 대해 설명하고 있다.

다음 코드는 "hello"를 인쇄하고 1초를 기다린 다음 "world"를 인쇄한다.

import asyncio

async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')

asyncio.run(main())

 

코루틴 함수를 만들기 위해는 함수 앞에 async 키워드를 붙여주면 된다.

await는 어웨이터블 객체만 사용할 수 있으며, 코루틴 내에서 다른 코루틴을 호출하고 결과를 받을 때 사용된다.

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

약 3초가 걸린다.

위의 코드는 단순 코루틴을 호출하는 것이지 여러 코루틴을 동시에 실행하는 것은 아니다.

 

asyncio.create_task()로 태스크를 실행하도록 예약해야 한다.

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # await say_after(1, 'hello')
    # await say_after(2, 'world')

    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

2초로 줄어드는 걸 볼 수 있다.

asyncio.gather로 여러 태스크를 한번에 등록할 수 있다.

 

 

다른 예제를 살펴보자.

네이버, 구글, 인스타그램을 각각 10번씩 요청해서 그에 대한 응답을 가져오는데, 약 10초정도 소요된다.

import requests
import time


def fetcher(session, url):
    with session.get(url) as response:
        return response.text


def main():
    urls = ["https://naver.com", "https://google.com",
            "https://instagram.com"] * 10

    with requests.Session() as session:
        result = [fetcher(session, url) for url in urls]
        print(result)


if __name__ == "__main__":
    start = time.time()
    main()
    end = time.time()
    print(end - start)

 

위의 코드를 비동기 코드로 변경해보자.

우선 aiohttp 패키지가 필요하므로 이를 pip를 이용해서 설치하고 변경하면 아래와 같다.

import aiohttp
import time
import asyncio


async def fetcher(session, url):
    async with session.get(url) as response:
        return await response.text()


async def main():
    urls = ["https://naver.com", "https://google.com", "https://instagram.com"] * 10

    async with aiohttp.ClientSession() as session:
        result = await asyncio.gather(*[fetcher(session, url) for url in urls])
        print(result)


if __name__ == "__main__":
    start = time.time()
    asyncio.run(main())
    end = time.time()
    print(end - start)

약 3초정도 걸린다.

 

적절한 때에 비동기 형태로 코드를 구성하면 많은 시간을 단축할 수 있다.

 

 

 

References:

https://docs.python.org/ko/3/library/asyncio-task.html

 

코루틴과 태스크 — Python 3.10.7 문서

코루틴과 태스크 이 절에서는 코루틴과 태스크로 작업하기 위한 고급 asyncio API에 관해 설명합니다. Coroutines declared with the async/await syntax is the preferred way of writing asyncio applications. For example, the follo

docs.python.org

https://github.com/amamov/teaching-async-python

 

GitHub - amamov/teaching-async-python: [인프런] 파이썬 동시성 프로그래밍 (feat. FastAPI)

[인프런] 파이썬 동시성 프로그래밍 (feat. FastAPI). Contribute to amamov/teaching-async-python development by creating an account on GitHub.

github.com

 

반응형