Python-Asnycio 비동기 프로그래밍

서동현·2023년 2월 8일
0

What is Asnyc 비동기 프로그래밍

프로그램이 여러가지 일을 수행해야할 때 선택할 수 있는 수행방법이 세가지다.
A,B,C의 Task를 수행해야 하는 경우
1. A -> B -> C를 순서대로 실행하는 경우(동기 프로그래밍)
2.
A
B 여러 스레드를 활용하여 동시에 수행 (Multi-Thread)
C
3.
A
#B : A 작업이 완료되기를 기다리는 동안 B 수행,
##C : B 작업이 완료되기를 기대리는 동안 C 수행.
비동기 프로그램은 3번방식으로 Task를 수행해서 메모리는 순간적으로 많이 사용할 수 있지만, 프로그램 실행속도를 빠르게 할 수 있다.

How to implement Asnyc Program in python

Asnycio Module

import asnycio

asnycio 모듈을 import한다.

Event loop

비동기 프로그램은 막힘이 없이 계속 돌아야하기 때문에
막히더라도 다음을 실행하는 기능을 가진 Loop를 생성한다.

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close

run_until_complete 함수에 의해 main function이 loop에 의해 완료될 때까지 실행된다.
main function이 완료되면 프로그램을 종료하기 위해 loop.close 함수로 loop를 끝내준다.

Coroutine

멀티 태스킹이 가능한 함수를 비동기에서 coroutine이라고 부른다.
asnyc를 붙여서 정의해준다.

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())

await는 coroutine을 실행하는 예약어이다.
awaitable 객체는 coroutine, task, future다.
아래와 같이 await가 여러개 있으면 호출한 코루틴 객체를 동기적으로 수행한다.
위의 경우 say_after 코루틴 객체를 호출하고, 동기적으로 asyncio.sleep과 print를 수행하고 동기적으로 다음 say_after 코루틴 객체를 호출하고 동기적으로 asyncio.sleep과 print를 수행한다.

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')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

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

하지만 create_task로 task를 만들면
coroutine을 호출하고, 비동기적으로 수행하기 때문에
위의 경우 두 say_after 코루틴객체가 호출과 동시에 비동기적으로 수행되어
await에서 그 결과의 반환만을 동기적으로 수행한다.

결론적으로 async로 생성된 coroutine은 await로 실행되는 함수로 이해해도된다.
coroutine으로 정의되지 않은 일반함수도
loop.run_in_executor()함수를 통해 coroutine으로 만들 수 있다.

async def getpage(url):
    req = await loop.run_in_executor(None, requests.get,
                                                               url)
    html = req.text
    soup = await loop.run_in_executor(None, BeautifulSoup,
                            html, 'lxml')
    return soup

loop.run_in_executor()함수의 첫번째 인자는 executor로 None으로 넣어도 된다.
두번째 인자는 실행하고자 하는 함수, 세번째부터는 그 함수에 입력할 인자이다.

Proplem

ipynb

Jupyter Notebook에서 asyncio module을 import해서
event loop을 실행시키는 과정에서
발생한 Error message : This event loop is already running
스크립트 초반부에 아래 코드를 추가하여 해결했다.

import asyncio
import nest_asyncio
nest_asyncio.apply()
profile
AI 비즈니스 가치를 고민합니다.

0개의 댓글