[Python] 파이썬 동시성- 코루틴

728x90

파이썬에서 코루틴이란 단일(싱글) 스레드에서 스택을 기반으로 동작하며 비동기작업을 쉽게 할 수 있도록 도와주는 도구입니다. 코루틴은 루틴 실행중 서브루틴을 호출하고 서브루틴에서 수행하는데  이 코루틴의 특징으로는 루틴 실행중 중지되었을 때 해당 위치를 기억하므로 동시성 프로그래밍을 할 수 있도록 도와줍니다.

이외에도 여러 장점으로는 스레드에 비해 오버헤드가 감소하며 스레드와 달리 단일 스레드로 동작하기 때문에 컨텍스트 스위칭 비용이 발생하지 않는다는 등이 있습니다.

 

아래사이트에서 개념을 더 확실히 익힐 수 있습니다.

https://velog.io/@jaebig/python-%EB%8F%99%EC%8B%9C%EC%84%B1-%EA%B4%80%EB%A6%AC-3-%EC%BD%94%EB%A3%A8%ED%8B%B4Coroutine

 

python 동시성 관리 (3) - 코루틴(Coroutine)이란?

들어가기에 앞서 이번 시간에는 코루틴 개념에 관하여 알아보도록 하겠습니다. 프로세스(Process)와 스레드(Thread) 개념 Python GIL(Global Interpreter Lock) 코루틴(Coroutine) 동시성 관리 구현에 유용한 모듈

velog.io

 

이 코루틴에서는 yield와 send 키워드가 사용되는데 이 키워드는 코루틴을 제어하고 양방향 전송을 할수 있도록 합니다.

파이썬 3.5이상에서는 def 키워드를 async로 , yield 키워드를 await로 사용 가능합니다.

 

예제를 통해서 살펴보겠습니다.

def coroutine_ex1():
    print("코루틴 시작")
    i = yield
    print(f"코루틴 받음: {i}")

# 메인 루틴
# 제너레이터 선언
gen1 = coroutine_ex1()
print(gen1,type(gen1)) #출력: <generator object coroutine_ex1 at 0x000001DEFA229740> <class 'generator'>

# yield 지점까지 서브루틴 수행
next(gen1) #출력: 코루틴 시작

# gen1.send(100) # 값 전송 -> 기본전달값은 none
#출력: 코루틴 받음: 100
# StopIteration 에러 -> 이후로 yield가 없기 때문에

gen2 = coroutine_ex1()
# next함수를 호출한 후 send 메소드 사용 가능
# gen2.send(100) # 출력: TypeError: can't send non-None value to a just-started generator

# 코루틴 상태값 확인
# GEN_CREATED : 처음 대기 상태
# GEN_RUNNIMG: 실행상태
# GEN_SUSPENDED: yield 대기 상태
# GEN_CLOSED : 실행완료 상태

def coroutine_ex2(x):
    print(f"코루틴 시작 {x}")
    y= yield x # 양방향 -> 오른쪽에 있는 주는 것, 왼쪽에 있으면 받는 것
    print(f"코루틴 받음 {y}")
    z = yield x+y
    print(f"코루틴 받음 {z}")

cr1 = coroutine_ex2(10)

from inspect import getgeneratorstate

print(getgeneratorstate(cr1)) #출력: GEN_CREATED

print(next(cr1))
#출력:
# 코루틴 시작 10
# 10
print(getgeneratorstate(cr1)) #출력: GEN_SUSPENDED

print(cr1.send(100))
#출력:
# 코루틴 받음 100
# 110

#파이썬 3.5이상에서 StopIteration를 자동처리(await)
# 중첩 코루틴

def coroutine_ex3():
    for x in 'AB':
        yield x

    for y in range(1,4):
        yield y

cr2 = coroutine_ex3()
print(next(cr2)) #출력: A
print(next(cr2)) #출력: B
print(next(cr2)) #출력: 1
print(next(cr2)) #출력: 2
print(next(cr2)) #출력: 3

cr3 = coroutine_ex3()
print(list(cr3)) #출력: ['A', 'B', 1, 2, 3]

def coroutine_ex4():
    yield from 'AB' # yield가 끝날때까지 순차적으로 반환
    yield from range(1,4)

cr3 = coroutine_ex4()
print(next(cr3)) #출력: A
print(next(cr3)) #출력: B
print(next(cr3)) #출력: 1
print(next(cr3)) #출력: 2
print(next(cr3)) #출력: 3