1. 학습목표

2. 학습내용
# 흐름제어, 병행처리(Concurrency)
# yield
# 코루틴 (coroutine)
# yield : 메인루틴과 서브루틴 간의 통신을 가능하게 함
# 서브루틴을 동시에 여러개 수행할 수 있도록 하는 것이 yield!!
# 코루틴 제어, 코루틴 상태, 양방향 값 전송
# yield from
# 서브루틴 : 메인루틴에서 리턴에 의해 호출 부분으로 돌아와 다시 프로세스를 시작
# 코루틴 : 루틴 실행 중에 멈춤 가능! 특정 위치로 돌아갔다가 다시 원래 위치로 돌아와 수행 가능!
# 코루틴을 통해 동시성 프로그래밍 가능!!!
# 코루틴은 스케줄링 오버헤드가 매우 적다! 왜냐하면 하나의 쓰레드에서 수행되기 때문!
# 쓰레드 : 싱글쓰레드 vs. 멀티스레드
# 멀티스레드의 단점:
# 멀티스레드는 복잡!
# 공유되는 자원에 대한 "교착상태" 발생 가능성!
# context switch 비용이 있음!
# 자원소비 가능성 증가!
# 코루틴 예제 #1
# 코루틴은 여러개의 서브 루틴을 "비동기"적으로 실행한다!
def coroutine1():
print('>>> coroutine started.')
i = yield
print('>>> coroutine received : {}'.format(i))
# 제너레티어 선언
c1 = coroutine1()
# 코루틴은 제너레이터다!
# print('EX1-1 -', c1, type(c1))
# EX1-1 - <generator object coroutine1 at 0x102415a20> <class 'generator'>
# # yield 실행 전까지 실행
# next(c1)
# # >>> coroutine started.
#
# # 기본으로 메인루틴이 None 값 전달
# # next(c1)
#
# # 실제 데이터를 전달할 수 있음!
# c1.send(100)
# '''
# >>> coroutine received : 100
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 46, in <module>
# c1.send(100)
# StopIteration
# '''
# 잘못된 사용
# c2 = coroutine1()
# # c2.send(100) # 제너레이터가 아직 시작되지 않았기 때문에 이렇게하면 에러 발생!
# # """
# # Traceback (most recent call last):
# # File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 60, in <module>
# # c2.send(100)
# # TypeError: can't send non-None value to a just-started generator
# # """
# c3 = coroutine1()
# next(c3)
# c3.send(100)
# """
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 71, in <module>
# c3.send(100)
# StopIteration
# >>> coroutine started.
# >>> coroutine received : 100
# """
# 코루틴 예제#2
# 코루틴의 상태를 보여주는 좋은 메소드들
# GEN_CREATED : 처음 대기 상태
# GEN_RUNNING : 실행 상태
# GEN_SUSPENDED : yield 대기 상태
# GEN_CLOSED : 실행 완료 상태
def coroutine2(x):
print('>>> coroutine started : {}'.format(x))
# y는 메인루틴이 코루틴한테 전달하는 값 / x는 코루틴이 메인루틴에게 전달하는 값
y = yield x
print('>>> coroutine received : {}'.format(y))
z = yield x + y
print('>>> coroutine received : {}'.format(z))
c4 = coroutine2(10)
from inspect import getgeneratorstate
# print('EX1-2 -', getgeneratorstate(c4))
# # EX1-2 - GEN_CREATED
# print(next(c4))
# '''
# >>> coroutine started : 10
# 10
# '''
# print('EX1-3 -', getgeneratorstate(c4))
# # EX1-3 - GEN_SUSPENDED
# print(c4.send(15))
# '''
# >>> coroutine received : 15
# 25
# '''
# print(c4.send(20))
# '''
# >>> coroutine received : 20
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 116, in <module>
# print(c4.send(20))
# StopIteration
# '''
# 데코레이터 패턴
# 코루틴을 맨처음 실행할 때는 항상 next를 실행해주었어야 했다
# 최초에 next를 실행해줘야하는 부분을 데코레이터 패턴으로 해결해보자
from functools import wraps
def coroutine(func):
''' Decorator run until yield '''
@wraps(func) # 이 데코레이터의 의미는?! 이게 없어도 동작은 함!
def primer(*args, **kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer
@coroutine
def sumer():
total = 0
term = 0
while True:
term = yield total
total += term
su = sumer()
# print('EX2-1 -', su.send(100))
# # EX2-1 - 100
# print('EX2-2 -', su.send(40))
# # EX2-2 - 140
# print('EX2-2 -', su.send(60))
# # EX2-2 - 200
# 코루틴에 예외를 던져서 멈춰보기
class SampleException(Exception):
''' 설명에 사용할 예외 유형 '''
def coroutine_except():
print('>> coroutine started.')
try:
while True:
try:
x = yield
except SampleException:
print('-> SampleException handled. Continuing ..')
else:
print('-> coroutine recieved : {}'.format(x))
finally:
print('-> coroutine ending')
exe_co = coroutine_except()
# print('EX3-1 -', next(exe_co))
# print('EX3-2 -', exe_co.send(10))
# print('EX3-3 -', exe_co.send(100))
# print('EX3-4 -', exe_co.throw(SampleException))
# print('EX3-5 -', exe_co.send(1000))
# print('EX3-6 -', exe_co.close()) # GEN_CLOSED
# print('EX3-7 -', exe_co.send(10))
# '''
# >> coroutine started.
# EX3-1 - None
# -> coroutine recieved : 10
# EX3-2 - None
# -> coroutine recieved : 100
# EX3-3 - None
# -> SampleException handled. Continuing ..
# EX3-4 - None
# -> coroutine recieved : 1000
# EX3-5 - None
# -> coroutine ending
# EX3-6 - None
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 191, in <module>
# print('EX3-7 -', exe_co.send(10))
# StopIteration
# '''
# 코루틴 예제 #4 (return)
def averager_re():
total = 0.0
cnt = 0
avg = None
while True:
term = yield
if term is None:
break
total += term
cnt += 1
avg = total / cnt
return 'Average : {}'.format(avg)
avger2 = averager_re()
next(avger2)
avger2.send(10)
avger2.send(30)
avger2.send(50)
# try:
# avger2.send(None)
# except StopIteration as e:
# print('EX4-1 -', e.value)
# # EX4-1 - Average : 30.0
# 코루틴 예제5(yield from)
# 매우 중요!!!
# StopIteration을 자동처리해줌! (3.7 이후부터는 await로 바뀜!)
# 중첩 코루틴 처리
def gen1():
for x in 'AB':
yield x
for y in range(1,4):
yield y
t3 = gen1()
# print('EX6-1 -', next(t3))
# print('EX6-2 -', next(t3))
# print('EX6-3 -', next(t3))
# print('EX6-4 -', next(t3))
# print('EX6-5 -', next(t3))
# print('EX6-6 -', next(t3))
# '''
# EX6-1 - A
# EX6-2 - B
# EX6-3 - 1
# EX6-4 - 2
# EX6-5 - 3
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 260, in <module>
# print('EX6-6 -', next(t3))
# StopIteration
# '''
t2 = gen1()
# print('EX6-7 -', list(t2))
# # EX6-7 - ['A', 'B', 1, 2, 3]
def gen2():
yield from 'AB'
yield from range(1,4)
t3 = gen2()
# print('EX6-1 -', next(t3))
# print('EX6-2 -', next(t3))
# print('EX6-3 -', next(t3))
# print('EX6-4 -', next(t3))
# print('EX6-5 -', next(t3))
# print('EX6-6 -', next(t3))
# '''
# EX6-1 - A
# EX6-2 - B
# EX6-3 - 1
# EX6-4 - 2
# EX6-5 - 3
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 290, in <module>
# print('EX6-6 -', next(t3))
# StopIteration
# '''
t4 = gen2()
# print('EX6-7 -', list(t4))
# EX6-7 - ['A', 'B', 1, 2, 3]
def gen3_sub():
print('sub coroutine.')
x = yield 10
print('Recv : ',str(x))
x = yield 100
print('Recv : ',str(x))
def gen4_main():
yield from gen3_sub()
t5 = gen4_main()
# print('EX7-1 -', next(t5))
# print('EX7-2 -', t5.send(7))
# print('EX7-2 -', t5.send(77))
# '''
# Traceback (most recent call last):
# File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 326, in <module>
# print('EX7-2 -', t5.send(77))
# StopIteration
# sub coroutine.
# EX7-1 - 10
# Recv : 7
# EX7-2 - 100
# Recv : 77
# '''
3. 느낀 점