코루틴
: 루틴의 일종으로서, 협동 루틴이라 할 수 있다.진입점(entry point)
이라고 하는데, 코루틴은 진입점이 여러 개인 함수입니다.
generator
: next 함수를 반복 호출하여 값을 얻어낸다.
coroutine
: next 함수를 한번만 호출한 뒤 send로 값을 주고 받는 방식이다.
def number_coroutine():
while True: # 코루틴을 계속 유지하기 위해 무한 루프 사용
x = (yield) # 코루틴 바깥에서 값을 받아옴, yield를 괄호로 묶어야 함
print(x)
co = number_coroutine()
next(co) # 코루틴 안의 yield까지 코드 실행(최초 실행)
# co.send(None), co.__next__()
co.send(1) # 코루틴에 숫자 1을 보냄
co.send(2) # 코루틴에 숫자 2을 보냄
co.send(3) # 코루틴에 숫자 3을 보냄
# 1
# 2
# 3
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() # 코루틴 종료
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
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()
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 코루틴 종료
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, '예외로 코루틴 끝내기'))
# 예외가 발생하면 에러 메시지를 출력하고
# 코루틴의 except에서 yield로 전달받은 누적된 값을 출력
# 예외로 코루틴 끝내기
# 190
import time
def coroutine_test():
greeting = "good"
while True:
text = (yield greeting)
print("text= ", end= ""), print(text)
greeting += text
if __name__ == "__main__":
cr = coroutine_test()
print("cr=", end=""), print(cr)
next(cr) # 코루틴 최초 실행 'good' 저장
time.sleep(2)
print("send 1")
print(cr.send("morning")) # 마지막으로 저장된 'good' 뒤에서 실행을 재개
time.sleep(2)
print("send 2")
print(cr.send("afternoon"))
time.sleep(2)
print("send 3")
print(cr.send("evening"))
time.sleep(2)
# cr=<generator object coroutine_test at 0x000001F301A0CF90>
# send 1
# text= morning
# goodmorning
# send 2
# text= afternoon
# goodmorningafternoon
# send 3
# text= evening
# goodmorningafternoonevening
# 해결방법1
def coroutine_test():
greeting = "good"
while True:
text = (yield greeting)
print(greeting + text)
if __name__ == "__main__":
cr = coroutine_test()
print("cr=", end=""), print(cr)
next(cr)
time.sleep(2)
print("send 1")
cr.send("morning")
time.sleep(2)
print("send 2")
cr.send("afternoon")
time.sleep(2)
print("send 3")
cr.send("evening")
time.sleep(2)
# cr=<generator object coroutine_test at 0x0000026EAF53CF90>
# send 1
# goodmorning
# send 2
# goodafternoon
# send 3
# goodevening
# 해결방법2
def coroutine_test():
greeting = "good"
while True:
text = (yield greeting)
print("text = ", end=""), print(text)
greeting = "good" # greeting 초기화
greeting += text
if __name__ == "__main__":
cr = coroutine_test()
print("cr=", end=""), print(cr)
next(cr)
time.sleep(2)
print("send 1")
print(cr.send("morning"))
time.sleep(2)
print("send 2")
print(cr.send("afternoon"))
time.sleep(2)
print("send 3")
print(cr.send("evening"))
time.sleep(2)
# cr=<generator object coroutine_test at 0x000001743551CF90>
# send 1
# text = morning
# goodmorning
# send 2
# text = afternoon
# goodafternoon
# send 3
# text = evening
# goodevening
# 코루틴 2개로 일억을 증가시키는 예제
def coroutine_1():
return_value = 0
while True:
input_value = (yield return_value)
return_value = input_value + 1
def coroutine_2():
return_value = 0
while True:
input_value = (yield return_value)
return_value = input_value + 1
if __name__ == "__main__":
ret_value = 0
c1 = coroutine_1()
c2 = coroutine_2()
next(c1)
next(c2)
while ret_value < 100000000:
ret_value = c1.send(ret_value)
ret_value = c2.send(ret_value)
print("ret_value =", end=""), print(ret_value)
print("end of main")
# ret_value =100000000
# end of main
asyncio(Asynchronous I/O)
import asyncio
async def coroutine_1(num): # 네이티브 코루틴 생성
result_value = 0
while result_value < num:
result_value += 1
return result_value
async def coroutine_2(num):
result_value = 0
while result_value < num:
result_value += 1
return result_value
async def main():
# await : 해당 객체가 끝날 때까지 기다린 뒤 결과 반환
one = await coroutine_1(50000000)
two = await coroutine_2(50000000)
# await asyncio.sleep(1.0) -> 1초 대기, asyncio.sleep도 네이티브 코루틴
print("ret_value=", end="")
print(one+two)
print("end of main")
if __name__ == "__main__":
loop = asyncio.get_event_loop() # 이벤트 루프를 얻음
loop.run_until_complete(main()) # main이 끝날 때까지 기다림
loop.close() # 이벤트 루프를 닫음
# ret_value=100000000
# end of main