[python] 코루틴 사용하기

anjiyoo·2024년 3월 20일

Python

목록 보기
39/41
post-thumbnail

1.코루틴

  • 함수는 메인 루틴에서 서브 루틴을 호출하면 서브 루틴의 코드를 실행 한 뒤 다시 메인 루틴으로 돌아옴
    서브 루틴이 끝나면 서브 루틴의 내용이 모두 사라짐
    서브 루틴은 메인 루틴에 종속된 관계
  • 코루틴은 두 루틴이 대등한 관계인 상태에서 특정 시점에 상대방의 코드를 실행하는 방식
  • 코루틴은 코드를 여러 번 실행할 수 있음
    1. 함수가 종료되지 않은 상태에서 메인 루틴의 코드를 실행 한 뒤
    2. 다시 돌아와서 코루틴의 코드를 실행
    3. 코루틴이 종료되지 않았으므로 코루틴의 내용도 계속 유지
def 코루틴이름():
	while True:
    변수 = (yield)  # 코루틴 바깥에서 값을 받아옴
    
코루틴객체 = 코루틴()
next(코루틴객체)  # 코루틴 안의 yield까지 코드 실행(최초 실행), __next__메소드도 같음
코루틴객체.send(값)  # 코루틴에 값을 보냄
def 코루틴이름():
	while True:
    변수 = (yield 변수)  # 코루틴 바깥에서 값을 받아오면서 바깥으로 값을 전달
    
코루틴객체 = 코루틴()
변수 = next(코루틴객체)  # 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 반환
변수 = 코루틴객체.send(값)  # 코루틴에 값을 보내고 코루틴에서 나온 값 반환

1-2.코루틴에 값 보내기

  • 코루틴은 제너레이터의 특별한 형태
  • yield로 값을 발생시켰지만 코루틴은 yield로 값을 받아올 수 있음
  • send 메소드가 보낸 값을 받아오려면 (yield) 형식으로 변수에 저장
코루틴객체.send(값)
변수 = (yield)
next(코루틴객체)
def number_coroutine():
	while Ture:  # 코루틴을 계속 유지하기 위해 무한 루프 사용
    	x = (yield)  # 코루틴 바깥에서 값을 받아옴
        print(x)
        
co = number_coroutine()
next(co)  # 코루틴 안의 yield까지 코드 실행(최초 실행)

co.send(1)  # 코루틴에 숫자 1을 보냄
co.send(2)  # 코루틴에 수자 2를 보냄
co.send(3)  # 코루틴에 숫자 3을 보냄
  • 코루틴은 yield에서 함수 중간에 대기한 다음 메인 루틴을 실행하다가 다시 코루틴을 실행함

2.코루틴 바깥으로 값 전달하기

  • (yield 변수) 형식으로 yield에 변수를 지정한 뒤 괄호로 묶어주면 값을 받아오면서
    값을 바깥으로 전달
  • next는 코루틴의 코드를 실행하지만 값을 보내지 않을 때 사용
  • send는 값을 보내면서 코루틴의코드를 실행할 때 사용
변수 = (yield 변수)
변수 = next(코루틴객체)
변수 = 코루틴객체.send(값)
def sum_coroutine():
	total = 0
    while True:
    	x = (yield total)  # 코루틴 바깥에서 갑을 받아오면서 바깥으로 값을 전달
        total += x
        
co = sum_coroutine()
print(next(co))  # 0: 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력

print(co.send(1))  # 1: 코루틴에 숫자 1을 보내고 코루틴에서 나온 값 출력
print(co.send(2))  # 3: 코루틴에 숫자 2를 보내고 코루틴에서 나온 값 출력
print(co.send(3))  # 6: 코루틴에 숫자 3을 보내고 코루틴에서 나온 값 출력
  1. 코루틴에서 값을 누적할 변수 total을 만들고 0 할당
  2. x = (yield total)과 같이 값을 받아오면서 바깥으로 값을 전달
  3. 바깥에서 send가 보낸 값은 n에 저장
  4. 코루틴 바깥으로 보낼 값은 total

2-1.제너레이터 vs 코루틴

  • 제너레이터 : next 함수 __next__메소드를 반복 호출하여 값을 얻어내는 방식
  • 코루틴 : next 함수 __next__메소드를 한번 호출한 뒤 send로 값을 주고받는 방식

3.코루틴을 종료하고 예외 처리하기

  • 코루틴은 실행 상태를 유지하기 위해 while True:를 사용해서 무한 루프로 동작
  • 코루틴을 강제로 종료하고 싶다면 close 메소드를 사용
  • 코루틴 객체에서 close 메소드를 사용하면 코루틴 종료
def 코루틴이름():
	try:
    	실행할 코드
    except GeneratorExit:  # 코루틴이 종료될 때 GeneratorExit 예외 발생
    	예외가 발생했을 때 처리하는 코드
        
코루틴객체 = 코루틴()
next(코루틴객체)
코루틴객체.close()  # 코루틴 종료
def 코루틴이름():
	try:
    	실행할 코드
    except 예외이름 as e:  # e에는 throw 메소드에 지정한 에러 메시지에 들어감
    	yield 값  # except에서 yield에 지정한 값은 throw 메소드의 반환값으로 나옴
        
코루틴객체 = 코루틴()
next(코루틴객체)
코루틴객체.throw(예외이름, 에러메시지)  # 코루틴 안에 예외를 발생시킴
def number_coroutine():
	while True:
    	x = (yield)
        print(x, end=' ')

co = number_coroutine()
next(co)

for i in range(20):
	co.send(i)
    
co.close()  # 코루틴 종료

3-1.GeneratorExit 예외 처리하기

  • 코루틴 객체에서 close 메소드 호출하면 코루틴이 종료될 때 GeneratorExit 예외가 발생
  • GeneratorExit 예외를 처리하면 코루틴의 종료 시점을 알 수 있음
def number_coroutine():
	try:
    	while True:
        	x = (yield)
            print(x, end=' ')
    except GeneratorExit:  # 코루틴이 종료될 때 GeneratorExit 예외 발생
    	print()
        print('코루틴 종료')
co = number_coroutine()
next(co)

for i in range(20):
	co.send(i)

co.close()

3-2.코루틴 안에 예외 발생시키기

  • 코루틴 안에 예외를 발생시킬 때는 throw 메소드를 사용
  • throw 메소드에 지정한 에러 메시지는 except as의 변수에 들어감
코루틴객체.throw(예외이름, 에러메시지)
def sum_coroutine():
	try:
    	total  0
        while True:
        	x = (yield)
            total += x
    except RuntimeError as e:
    print(e)
    yield total  # 코루틴 바깥으로 값 전달

co = sum_coroutine()
next(co)

for i in range(20):
	co.send(i)
    
print(co.throw(RuntimeError, '예외로 코루틴 끝내기'))  # 190. 코루틴의 except에서 yield로 전달받은 값

4.하위 코루틴의 반환값 가져오기

  • yield from에 코루틴을 지정하면 해당 코루틴에서 return으로 반환값 가져옴
변수 = yield from 코루틴()
def 코루틴A():
	변수 = (yield)  # 코루틴 바깥에서 값을 받아옴
    return 값  # return으로 값을 반환, raise StopIteration(값)과 동작이 같음

def 코루틴B():
	변수 = yield from 코루틴A()  # 코루틴A의 반환값을 가져옴
def accmulate():
	total = 0
    while True:
    	x = (yield)   # 코루틴 바깥에서 값을 받아옴
        if x in None:   # 받아온 값이 None이면
        	return total  # 합계 total을 반환
        total += x
        
def sum_coroutine():
	while True:
    	total = yield from accumulate()   # accumulate의 반환값을 가져옴
        print(total)
        
co = sum_coroutime()
next(co)

for i in range(1, 11):   # 1부터 10까지 반복
	co.send(i)  # 코루틴 accumulate에 숫자를 보냄
co.send(None)   # 코루틴 accumulate에 None을 보내서 숫자 누적을 끝냄
    
for i in range(1, 101):  # 1부터 100까지 반복
	co.send(i)   # 코루틴 accumulate에 숫자를 보냄
co.send(None)   # 코루틴 accumulate에 None을 보내서 숫자 누적을 끝냄

4-1.Stoplteration 예외 발생시키기

  • 코루틴도 제너레이터이므로 return을 사용하면 Stoplteration이 발생
  • raise로 예외를 직접 발생시키고 값을 지정하면 yield from으로 값을 가져올 수 있음
raise Stoplteration(값)
def accmulate():
	total = 0
    while True:
    	x = (yield)   # 코루틴 바깥에서 값을 받아옴
        if x in None:   # 받아온 값이 None이면
        	raise Stoplteration(total)  # Stoplteration에 반환할 값을 지정
        total += x
        
def sum_coroutine():
	while True:
    	total = yield from accumulate()   # accumulate의 반환값을 가져옴
        print(total)
        
co = sum_coroutime()
next(co)

for i in range(1, 11):   # 1부터 10까지 반복
	co.send(i)  # 코루틴 accumulate에 숫자를 보냄
co.send(None)   # 코루틴 accumulate에 None을 보내서 숫자 누적을 끝냄
    
for i in range(1, 101):  # 1부터 100까지 반복
	co.send(i)   # 코루틴 accumulate에 숫자를 보냄
co.send(None)   # 코루틴 accumulate에 None을 보내서 숫자 누적을 끝냄
profile
기록으로 흔적을 남기는 것을 좋아합니다

0개의 댓글