UNIT41 코루틴 사용하기

지금까지 함수를 호출한 뒤 함수가 끝나면 현재 코드로 다시 돌아왔습니다. 메인 루틴에서 서브 루틴을 호출하면 서브 루틴의 코드를 실행한 뒤 다시 메인 루틴으로 돌아오고, 서브 루틴이 끝나면 서브 루틴의 내용은 모두 사라졌습니다.

코루틴은 각 루틴이 종속적인 관계가 아닌 대등한 관계로서, 특정 시점에 상대방의 코드를 실행하게 되어있는 함수입니다. 일반 함수를 호출하면 코드를 한 번만 실행할 수 있지만, 코루틴은 코드를 여러 번 실행할 수 있습니다. 함수의 코드를 실행하는 지점을 진입점(entry point)라고 하는데, 코루틴은 진입점이 여러 개인 함수입니다.

코루틴에 값 보내기

코루틴은 제너레이터의 특별한 형태입니다. 제너레이터에서 값을 발생 시킬 때 사용했던 yield로 코루틴은 값을 받아옵니다. 코루틴의 값은 메인루틴에서 send 메서드를 이용해 보내줍니다. send를 통해 받은 값을 사용하기 위해 yield를 괄호로 묶어 변수에 할당해줍니다.

  • 코루틴객체.send(값)
  • 변수 = (yield)
def number_coroutine():  
	while True :       # 코루틴을 계속 유지하기 위해 무한 루프 사용  
		x = (yield)    # 코루틴 바깥에서 값을 받아옴  
		print(x)  
  
co = number_coroutine()  
next(co)               # 코루틴 안의 yield 까지 코드 실행(최초 실행)  
  
co.send(1)     # 코루틴에 숫자 1을 보냄 -> number_coroutine은 1을 받아서 출력하고 다시 yield에서 대기  
co.send(2)     # 코루틴에 숫자 2을 보냄  
co.send(3)     # 코루틴에 숫자 3을 보냄  

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

코루틴은 바깥으로 값을 전달할 수도 있습니다. (yield 변수) 형식으로 yield에 변수를 지정한 뒤 괄호로 묶어주면 값을 받아오면서 바깥으로 값ㅇ르 전달합니다. 그리고 yield를 사용하여 바깥으로 전달한 값은 next 함수와 send 메서드의 반환값으로 나옵니다.

def sum_coroutine():  
	total = 0  
	while True :  
		x = (yield total)   # 코루틴 바깥으로 값을 전달하면서 바깥에서 값을 받아옴  
		total += x  
  
co = sum_coroutine()  
print(next(co))      # 0 -> yield 0 전달하는 것까지 실행하고 대기  
  
print(co.send(1))    # 1 -> yield가 1을 받고, 다음 yield 까지 실행해서 total 값 전달  
print(co.send(2))    # 3  
print(co.send(3))    # 6  

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

보통 코루틴은 실행 상태를 유지하기 위해 while True: 를 사용하여 끝나지 않는 무한 루프로 동작합니다. 코루틴을 강제로 종료하고 싶다면 close 메서드를 사용합니다.

  • 코루틴객체.close()

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()  

코루틴 안에 예외 발생시키기

def sum_coroutine():  
	try:  
		while True:  
		x = (yield )  
		total += x  
	except RuntimeError as e:        
		print(e)  
		yield total  
  
co = number_coroutine()  
next(co)  
  
for i in range(20):  
	co.send(i)  
  
print(co.throw(RuntimeError, '예외로 코루틴 끝내기'))  

하위 코루틴 값 가져오기

제너레이터에서 yield from 을 사용하면 값을 바깥으로 여러 번 전달한다고 했습니다. 하지만 코루틴에서는 yield from에 코루틴을 지정하면 해당 코루틴에서 return 으로 반환한 값을 가져옵니다.

def accumulate():  
	total = 0  
	while True :  
		x = (yield)  
		if x is None :  
			return total  
		total += x  
  
def sum_coroutine():  
	while True :  
		total = yield from accumulate()  
		print(total)  
  
co = sum_coroutine()  
next(co)               # accumulate의 yield 까지 가서 기다림  
  
for i in range(1,11):  
	co.send(i)         # accumulate 에 숫자 보냄  
co.send(None)          # accumulate 에 None을 보내서 return total 하고 끝남  
                       # 그리고 yield from 만나서 다시 accumulate 의 yield에서 대기  
  
for i in range(1, 101):  
	co.send(i)  
co.send(None)  

StopIteration 예외 발생 시키기

def accumulate():  
	total = 0  
	while True :  
		x = (yield)  
		if x is None :  
			raise StopIteration(total)  
		total += x  
  
def sum_coroutine():  
	while True :  
		total = yield from accumulate()  
		print(total)  
  
co = sum_coroutine()  
next(co)               # accumulate의 yield 까지 가서 기다림  
  
for i in range(1,11):  
	co.send(i)         # accumulate 에 숫자 보냄  
co.send(None)          # accumulate 에 None을 보내서 return total 하고 끝남  
                       # 그리고 yield from 만나서 다시 accumulate 의 yield에서 대기  
  
for i in range(1, 101):  
	co.send(i)  
co.send(None)  

코루틴은 함수가 종료되지 않은 상태에서 값을 주고받을 수 있는 함수이며 이 과정에서 현재 코드의 실행을 대기하고 상대방의 코드를 실행합니다. 보통 코루틴은 시간이 오래 걸리는 작업을 분할하여 처리할 때 사용하는데 주로 파일 처리, 네트워크 처리 등에 활용합니다.