본문 바로가기

Computer Science

Python - native coroutine

728x90

코루틴이란?

- 실행의 지연과 재개를 허용 함으로써, non-preemptive(비 선점적) 멀티태스킹을 위한 subroutine을 일반화

    - 서브루틴: 함수의 동작이 끝나면 자신을 호출하였던 메인루틴으로 돌아오는 루틴. 하나의 진입점과 하나의 탈출점

    - 코루틴: 루틴을 진행하는 중간 멈춰서 특정 위치로 돌아갔다가 다시 원래 위치로 돌아올 수 있는 루틴. (메인 루틴에 종속적이지 않음) 다양한 진입점과 다양한 탈출점

    - 비 선점형 멀티태스킹: 병렬이 아닌 병행성(Concurrency). -> 동시에 실행되는 것처럼 보임. CPU 사용권을 뺏을 수 없음. -> 작업 교환 때 비용이 적음.

- 싱글 스레드에서 동작하는 비동기 동시성(Concurrency) 작업

- 멀티스레드를 대체하기 위한 것이 아닌, 스레드에서 대기시간을 최소화하는 것

- CPU와 리소스 낭비 방지 가능

generator 기반 코루틴

- yield 을 통해서 메인 루틴과 서브 루틴간에 값을 이동하며 실행의 지연 및 재개.

generator 기반 코루틴 예시

# 출처: https://velog.io/@soojung61/Python-Coroutine

def coroutine():
    total = 0
    while True:
        num = yield total # total 발생 및 num에 값 저장
        total += num

cr = coroutine()
print(next(cr)) # 처음 yield 까지 실행
print(cr.send(3)) # num에 3 저장 후 다음 yield 까지 실행
print(cr.send(2)) # num에 2 저장 후 다음 yield 까지 실행

""" 실행결과
0
3
5
"""

native 코루틴

이것 저것 찾아보다보니.. 내용이 너무 많아서 간단한 기본 예제만 블로깅...!
여태껏 native 코루틴을 잘 모르고 파이썬을 사용 했었다니...

- asyncio 사용하여 구성된 코루틴

    - 파이썬에서 제공하는 동시성 프로그래밍

    - async/await 구문 사용

- async def 로 코루틴 함수 생성

- awaitawaitable 객체(코루틴 객체, 퓨처 객체, 태스트 객체) 실행 (native 코루틴 안에서만 사용 가능)

- asyncio.run(), asyncio.sleep(), asyncio.wait(), asyncio.gather(), asyncio.Queue() 등 사용

asyn/await 작동 원리

import time
import asyncio

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

def sync_say_after(delay, what):
    time.sleep(delay)
    print(what)

async def main():
    s = time.time()
    sync_say_after(3, "A")
    sync_say_after(2, "B")
    print(time.time() - s)

    s = time.time()
    await say_after(3, "A")
    await say_after(2, "B")
    print(time.time() - s)

    s = time.time()
    await asyncio.gather(
        say_after(3, "A"),
        say_after(2, "B")
    )
    print(time.time() - s)

asyncio.run(main())

 

위 코드의 실행 결과는 아래와 같다.

 

A
B
5.009169340133667
A
B
5.0119383335113525
B
A
3.009953260421753

 

await을 통해 awaitable 객체가 완료될 때 까지 대기된다. 따라서 동기적으로 진행되는 첫 예시와, 비동기지만 await으로 대기하는 두번째 예시는 비슷한 시간(3초 + 2초)이 소모된다.

 

세번째 예시의 경우 두 코루틴 함수 동시 실행 후, 늦게 종료되는 say_after(3, "A") 코드를 기다린다. 따라서 3초 정도의 시간만 소모한다. asyncio.gather

 

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

코루틴과 태스크 이 절에서는 코루틴과 태스크로 작업하기 위한 고급 asyncio API에 관해 설명합니다. async/await 문법으로 선언된 코루틴은 asyncio 응용 프로그램을 작성하는 기본 방법입니다. 예를

docs.python.org

 

task1 = asyncio.create_task(
    say_after(3, "A")
)

task2 = asyncio.create_task(
    say_after(2, "B")
)

await task1
await task2

 

이는 task로도 작성이 가능하다. 중요한 점은 await은 코드를 실행하는 것이 아닌, task의 완료를 대기하는 역할을 할 뿐이다. 위 예제에서 task는 생성되자 마자 바로 실행된다. asyncio.create_task

 

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

코루틴과 태스크 이 절에서는 코루틴과 태스크로 작업하기 위한 고급 asyncio API에 관해 설명합니다. async/await 문법으로 선언된 코루틴은 asyncio 응용 프로그램을 작성하는 기본 방법입니다. 예를

docs.python.org

비동기 프로그래밍이 아직 익숙하지 않지만, 현재 하고 있는 프로젝트에 당장 적용시켜보며 native 코루틴과 친해져야겠다.
다음 포스팅은 아마 적용한 코루틴 예시이거나 OS 기초 내용일 것 같다.

 

Refence

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

- velog.io/@soojung61/Python-Coroutine

- leo-bb.tistory.com/51

- jeongupark-study-house.tistory.com/180

- dojang.io/mod/page/view.php?id=2469

728x90

'Computer Science' 카테고리의 다른 글

Process vs Thread 정리  (0) 2021.03.31