IT/Python

코루틴

우루사이 2023. 11. 19. 13:03

코루틴이란

  • 동시성을 위해 사용자가 쪼갠 하위 구문을 대기시키고, 이어서 실행할는 기능
  • 함수 호출의 주/종 관계가 아니므로 시간에 관계 없이 n개의 작업을 대등 관계로 처리할 때 효과적
  • 코루틴은 실행 흐름을 저장 및 복원할 수 있어 대기 및 이어서 실행 가능
  • 코루틴 스케줄러는 한번에 하나의 코루틴만 이어서 실행하고 나머지는 대기 상태 유지

 

파이썬 코루틴

  • 제너레이터를 개선 사용, 쪼갤 하위 구문 앞에 yield 문 배치
  • 제너레이터의 일종이므로 호출 구문은 코루틴을 실행하는 것이 아니라 코루틴 객체만 생성
  • 코루틴 객체를 인자로 내장 함수 next()를 호출하면 yield까지 실행한 후 대기
  • 인자와 함께 코루틴 객체의 send() 메소드를 호출하면 다음 yield까지 실행
def co_func():
    # subroutine - init
    print("create")
    yield
    
    # subroutine - work
    print("start")
    yield
    
co = co_func()
a = next(co) # subroutine - init
co.send(None) # subroutine - work
co.send(None) # stopIteration 예외 발생
  • yield를 r-value로 사용하면 send() 메소드로부터 전달받은 인자를 l-value에 대입
  • yield 뒤 문장이 있다면 문장까지 실행 후 대기
data = []
def co_func(n):
    print("init co_func({0})".format(n))
    data1 = yield data.append(n)
    # yield 이전까지 실행(오른쪽 명령어)
    # 이후 send 메소드에 따라 받은 인자를 data1에 입력
    
    print("call subroutine1({0})".format(data1))
    data2 = yield data.append(n+data1)
    print("call subroutine2({0})".format(data2))
    yield
    
co = co_func(10)
next(co)
co.send(1)
co.send(2)

 

 

코루틴 상태

  • 생성, 실행, 대기, 종료 상태
  • 코루틴을 호출할 때 생성
  • 최초 실행은 next() 함수 호출 통해 수행, 이후 실행은 send() 메소드 호출 통해 수행
  • 명시적 종료는 close() 메소드 호출
# gen_created
co = coroutine()

# gen_running ~ "yield"
next(co)
# gen_suspended

# gen_running again
co.send()

# gen_closed
co.close()


# check_stat
from inspect import getgeneratorstate as co_stat
co_stat(co)

 

데코레이터로 코루틴 추상화

def co_routine(func):
    def wrapper(*args, **kwargs):
        # coroutine 초기화 구간
        co = func(*args, **kwargs)
        next(co)
        #####
        return co
    return wrapper

@co_routine
def foo():
    while True:
        yield

co = foo()
co.send(None)
co.close()

 

코루틴 결과 반환

@co_routine
def total():
    total = 0
    while True:
        term = yield
        if term == None:
            break
        total += term
    return total 
    # coroutine의 return은 StopIteration 예외 발생
    # 반환 대상은 예외 객체의 value 속성에 포함
    
co = total()
co.send(10)
co.send(20)
try:
    co.send(None)
except StopIteration as ret:
    print(ret.value)

 

코루틴과 함수 비교

구분 함수 코루틴
실행 부분 문장 모두 실행 다음 대기 구문사이만 부분적 실행
호출 후 호출 후 즉시 실행 호출 후 시작 상태만 설정
- next(): 설정
- send(): 실행
인자 호출 시 인자를 모두 넘김 실행 중에도 지속적으로 인자 넘길 수 있음
- send(인자)
상태 유지 속성, 전역 변수, 뮤터블 객체의 매개 변수 초기화 등 필요
- 함수의 상태를 유지하며 전달하려면, 전역 변수 활용
지역 변수로 충분

 

코루틴과 제너레이터 비교

구분 제너레이터 코루틴
특징 고차원적인 단방향 입력 이터레이터
- 입력으로 사용할 대상을 차례로 반환
데이터를 소비하는 이산적 처리에 사용
- 반복되는 시간이 일정치 않은 작업들을
   지속적으로 수행