PYTHON 프로그래밍

본문 바로가기
사이트 내 전체검색


PYTHON 프로그래밍
PYTHON 프로그래밍

제 13 장 동기/비동기 프로그램

페이지 정보

작성자 관리자 댓글 0건 조회 4,204회 작성일 20-08-17 21:35

본문

제 13 장 동기/비동기 프로그램

동기 프로그래밍


먼저 사용자 데이터 조회를 전통적인 동기 방식으로 처리해주는 find_users_sync 함수를 작성합니다.

의도적으로 1초의 지연 시간을 발생시키기 위해서 time.sleep 험수를 사용하였습니다.


import time


def find_users_sync(n):

    for i in range(1, n + 1):

        print(f'{n}명 중 {i}번 째 사용자 조회 중 ...')

        time.sleep(1)

    print(f'> 총 {n} 명 사용자 동기 조회 완료!')


그 다음, 애플리케이션에 들어온 3개의 요청을 동기 처리하는 process_sync 함수를 작성합니다.


def process_sync():

    start = time.time()

    find_users_sync(3)

    find_users_sync(2)

    find_users_sync(1)

    end = time.time()

    print(f'>>> 동기 처리 총 소요 시간: {end - start}')


if __name__ == '__main__':

    process_sync()


이 함수를 호출해보면 find_users_sync 함수가 총 6초 동안 3번 순차적으로 실행됨을 알 수 있습니다.


3명 중 1번 째 사용자 조회 중 ...

3명 중 2번 째 사용자 조회 중 ...

3명 중 3번 째 사용자 조회 중 ...

> 총 3 명 사용자 동기 조회 완료!

2명 중 1번 째 사용자 조회 중 ...

2명 중 2번 째 사용자 조회 중 ...

> 총 2 명 사용자 동기 조회 완료!

1명 중 1번 째 사용자 조회 중 ...

> 총 1 명 사용자 동기 조회 완료!

>>> 동기 처리 총 소요 시간: 6.020448923110962


만약에 싱글 쓰레드의 웹 서버가 이러한 방식으로 동작한다면 실제 사용자는 얼마나 오랫동안 지연을 경험을 하게 될까요?

동기 처리에서는 첫 번째 함수의 실행이 끝나야 두 번째 함수가 실행되고, 마찬가지로 두 번째 함수가 끝나야 세 번째 함수가 실행됩니다.

즉, 첫 번쨰 요청이 처리되는데는 3초, 두 번째 요청은 5초(3 + 2), 세 번째 요청은 6초(3 + 2 + 1)가 걸릴 것입니다.



비동기 프로그래밍


위에서 동기 처리되도록 작성된 코드를 파이썬의 async/await 키워드를 사용해서 한 번 비동기 처리될 수 있도록 개선해보도록 하겠습니다.

기존의 함수 선언에 async 키워드를 붙여서 일반 동기 함수가 아닌 비동기 함수(coroutine)로 변경하였으며, time.sleep 함수 대신에 asyncio.sleep 함수를 사용하여 1초의 지연을 발생시켰습니다.


time.sleep 함수는 기다리는 동안 CPU를 그냥 놀리는 반면에, asyncio.sleep 함수는 CPU가 놀지 않고 다른 처리를 할 수 있도록 해줍니다.

여기서 주의할 점은 asyncio.sleep 자체도 비동기 함수이기 때문에 호출할 때 반드시 await 키워드를 붙여야 한다는 것입니다.


import time

import asyncio


async def find_users_async(n):

    for i in range(1, n + 1):

        print(f'{n}명 중 {i}번 째 사용자 조회 중 ...')

        await asyncio.sleep(1)

    print(f'> 총 {n} 명 사용자 비동기 조회 완료!')


자 이제, 파이썬의 asyncio 라이브러리를 사용해서 위에서 작성한 함수를 비동기로 실행해보겠습니다.

먼저 이벤트 루프가 3개의 함수 호출을 알아서 스케줄하여 비동기로 호출할 수 있도록 asyncio.wait 함수의 배열 인자로 3개의 함수 리턴값, 즉 coroutine 객체를 넘겨주도록 수정합니다.

그리고 이렇게 수정된 process_async 비동기 함수를 호출할 때도, 함수의 리턴값인 coroutine 객체를, asyncio.run 함수에 넘겨줍니다.


async def process_async():

    start = time.time()

    await asyncio.wait([

        find_users_async(3),

        find_users_async(2),

        find_users_async(1),

    ])

    end = time.time()

    print(f'>>> 비동기 처리 총 소요 시간: {end - start}')


if __name__ == '__main__':

    asyncio.run(process_async())



비동기 처리되도록 재작성된 코드를 실행해보면 호출 순서와 무방하게 실행 시간이 짧은 수록 먼저 처리되는 것을 알 수 있습니다.

게다가 총 소요 시간도 6초에서 3초로 100% 단축되었음을 알 수 있습니다!


실제 사용자 관점에서 생각해보면 3초가 걸리는 요청을 기다리지 않고, 1초가 걸리는 요청은 1초 만에 응답이 오고, 2초가 걸리는 요청은 2초 만에 응답이 올테니 매우 이상적이지 않을 수 없습니다.


1명 중 1번 째 사용자 조회 중 ...

2명 중 1번 째 사용자 조회 중 ...

3명 중 1번 째 사용자 조회 중 ...

> 총 1 명 사용자 비동기 조회 완료!

2명 중 2번 째 사용자 조회 중 ...

3명 중 2번 째 사용자 조회 중 ...

> 총 2 명 사용자 비동기 조회 완료!

3명 중 3번 째 사용자 조회 중 ...

> 총 3 명 사용자 비동기 조회 완료!

>>> 비동기 처리 총 소요 시간: 3.0041661262512207


기본적으로 비동기 처리는 정확히 실행 순서가 보장되지 않기 때문에, 여러분 PC에서 실행했을 때는 저와 약간 실행 순서가 다를 수도 있습니다.

비록 동일한 실행 순서를 보장받지 못하더라도, 여기서 중요한 점은 CPU를 놀리지 않고 불필요한 지연없이 3개의 요청이 실행되어야 한다는 것입니다.

댓글목록

등록된 댓글이 없습니다.


개인정보취급방침 서비스이용약관 모바일 버전으로 보기 상단으로

TEL. 063-469-4551 FAX. 063-469-4560 전북 군산시 대학로 558
군산대학교 컴퓨터정보공학과

Copyright © www.leelab.co.kr. All rights reserved.