Concurrency #1 Generator

정은경·2020년 5월 5일

1. 학습목표

  • 동시성을 이해하는 데 'generator'의 깊은 이해가 필수적으로 선행되어야 함!
  • 제너레이터의 예약 키워드: yield

2. 학습내용

 # Generator

 # 동시성
 # 하나의 쓰레드 안에서 일어나는 분기를 처리해서 효율을 극대화

 # 병렬성
 # 하나의 계산을 병렬처리


# 동시성을 잘 이해하기 위해서는!
# generator에 대한 깊은 이해가 필요!

# 성능 위주로 코딩
# 여러개의 루틴을 분기해서 여러 개의 일을 처리!



# 흐름제어, 병행처래 => Concurrency
# 제너레이터, 반복형
# Generator


# 파이썬 반복형 종류
# for, collections, text file, list, dict, set, tuple, unpacking, *args
# 공부할 것: 반복형 객체 내부적으로 iter 함수 내용, 제너레이터 동작 원리, yield from


# 반복 가능한 이유? => iter라는 함수를 호출하기 때문

t = 'ABCDEF'

# for 사용
for c in t:
    # print('EX-1 -', c)
    pass

"""
EX-1 - A
EX-1 - B
EX-1 - C
EX-1 - D
EX-1 - E
EX-1 - F
"""


# while 사용
w = iter(t)
while True:
    try:
        next(w)
        # print('EX1-2 -', next(w))
    except StopIteration as log:
        print(log)
        break # break문이 없으면 무한반복되니 주의할 것!
"""
EX1-2 - A
EX1-2 - B
EX1-2 - C
EX1-2 - D
EX1-2 - E
EX1-2 - F
"""


from collections import abc

# 반복형 확인
# print('EX1-3 -', hasattr(t, '__iter__'))
# EX1-3 - True
# print('EX1-4 -', isinstance(t, abc.Iterable))
# EX1-4 - True


# next 사용
class WordSplitIter:
    def __init__(self, text):
        self._idx = 0
        self._text = text.split(' ')

    def __next__(self):
        print('Called __next__')
        try:
            word = self._text[self._idx]
        except IndexError:
            raise StopIteration('Stop! Stop!')
        self._idx += 1
        return word

    def __iter__(self):
        print('Called __iter__')
        return self

    def __repr__(self):
        return 'WordSplit(%s)' % (self._text)

wi = WordSplitIter('who says the nights are for sleeping')
# print(wi)
# WordSplit(['who', 'says', 'the', 'nights', 'are', 'for', 'sleeping'])

'''
print('EX3-1 -',next(wi))
print('EX3-2 -',next(wi))
print('EX3-3 -',next(wi))
print('EX3-4 -',next(wi))
print('EX3-5 -',next(wi))
print('EX3-6 -',next(wi))
print('EX3-7 -',next(wi))
print('EX3-8 -',next(wi))
'''

'''
Called __next__
EX3-1 - who
Called __next__
EX3-2 - says
Called __next__
EX3-3 - the
Called __next__
EX3-4 - nights
Called __next__
EX3-5 - are
Called __next__
EX3-6 - for
Called __next__
EX3-7 - sleeping
Called __next__
Traceback (most recent call last):
  File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 84, in __next__
    word = self._text[self._idx]
IndexError: list index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 109, in <module>
    print('EX3-8 -',next(wi))
  File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 86, in __next__
    raise StopIteration('Stop! Stop!')
StopIteration: Stop! Stop!
'''





## 제너레이터 사용하기
# Generator 패턴
# 1. 지능형 리스트, 딕셔너리, 집합의 데이터셋이 증가 될 경우! 메모리 사용량이 증가됨! 이를 제너레이터롤 완화!
# 2. 단위 실행 가능한 코루틴(coroutine) 구현에 아주 중요!!
# 3. 만들면서 하나씩 가져와고, 다음에 가지고 와야할 "위치"만 기억!
# 딕셔너리, 리스트는 한 번 호출 할 때마다 하나의 값을 리턴! 아주 작은 메모리 양을 필요로 함

# iter를 사용하면 index 정보등이 필요햇음
# generator로 더 간단하게 만들어 보자!
class WordSplitGenerator:
    def __init__(self, text):
        self._text = text.split(' ')

    def __iter__(self):
        for word in self._text:
            yield word # 제너레이터
        return

    def __repr__(self):
        return 'WordSplit(%s)' % (self._text)

wg = WordSplitGenerator('who says the nights are for sleeping')
# print(wg)
# WordSplit(['who', 'says', 'the', 'nights', 'are', 'for', 'sleeping'])


wt = iter(wg) # wg에는 next가 구현이 안되어서 iter함수에 wg넣어 줌

'''
print('EX3-1 -',next(wt))
print('EX3-2 -',next(wt))
print('EX3-3 -',next(wt))
print('EX3-4 -',next(wt))
print('EX3-5 -',next(wt))
print('EX3-6 -',next(wt))
print('EX3-7 -',next(wt))
print('EX3-8 -',next(wt))
'''
'''
EX3-1 - who
EX3-2 - says
EX3-3 - the
EX3-4 - nights
EX3-5 - are
EX3-6 - for
EX3-7 - sleeping
Traceback (most recent call last):
  File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 177, in <module>
    print('EX3-8 -',next(wt))
StopIteration
'''


# Generator 예제
def generator_ex1():
    print('start')
    yield 'AAA'
    print('continue')
    yield 'BBB'
    print('end')

# temp = iter(generator_ex1())
# print('EX4-1 -', next(temp))
# '''
# start
# EX4-1 - AAA
# '''
# print('EX4-1 -', next(temp))
# '''
# continue
# EX4-1 - BBB
# '''
# print('EX4-1 -', next(temp))
# '''
# Traceback (most recent call last):
#   File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 219, in <module>
#     print('EX4-1 -', next(temp))
# StopIteration
# '''


for v in generator_ex1():
    # print('EX4-3 -', v)
    pass
'''
start
EX4-3 - AAA
continue
EX4-3 - BBB
end
'''


# Generator 예제 #2
# temp2 = [x * 3 for x in generator_ex1()]
# temp3 = (x * 3 for x in generator_ex1()) # 제너레이터 생성 확인

# # print('EX5-1 -', temp2)
# '''
# start
# continue
# end
# start
# continue
# end
# EX5-1 - ['AAAAAAAAA', 'BBBBBBBBB']
# '''
#
# # print('EX5-1 -', temp3)
# '''
# start
# continue
# end
# start
# continue
# end
# EX5-1 - <generator object <genexpr> at 0x102ab3390>
# '''


# 리스트를 호출!!
# 이후 아래의 제너레이터의 출력결과와 비교해보세요!
# for i in temp2:
#     print('EX5-2 -', i)
# '''
# start
# continue
# end
# start
# continue
# end
# EX5-2 - AAAAAAAAA
# EX5-2 - BBBBBBBBB
# '''


# 제너레이터를 호출!! 적극 사용하세요!!
# 위의 리스트 호출 결과와 비교해보세요
# for i in temp3:
#     print('EX5-3 -', i)
# '''
# start
# continue
# end
# start
# continue
# end
# start
# EX5-3 - AAAAAAAAA
# continue
# EX5-3 - BBBBBBBBB
# end
# '''



# Generator 예제 3 (자주 사용하는 함수)
# generator는 next로 호출하기 전까지 계산식만 가지고 있고 호출하지 않는다!!!!!!!
import itertools

gen1 = itertools.count(1,2.5)
# print('EX6-1 -', next(gen1))
# print('EX6-1 -', next(gen1))
# print('EX6-1 -', next(gen1))
# print('EX6-1 -', next(gen1))
# '''
# start
# continue
# end
# EX6-1 - 1
# EX6-1 - 3.5
# EX6-1 - 6.0
# EX6-1 - 8.5
# '''



# 조건
gen2 = itertools.takewhile(lambda n : n < 10, itertools.count(1, 2.5))

for v in gen2:
    # print('EX6-5 -', v)
    pass
'''
start
continue
end
EX6-5 - 1
EX6-5 - 3.5
EX6-5 - 6.0
EX6-5 - 8.5
'''


# 필터 반대 역할 함수
gen3 = itertools.filterfalse(lambda  n : n <3, [1,2,3,4,5])

for v in gen3:
    # print('EX6-6 -', v)
    pass
'''
start
continue
end
EX6-6 - 3
EX6-6 - 4
EX6-6 - 5
'''


# 누적 합계
gen4 = itertools.accumulate([x for x in range(1,11)])

for v in gen4:
    # print('EX6-7 -', v)
    pass
'''
start
continue
end
EX6-7 - 1
EX6-7 - 3
EX6-7 - 6
EX6-7 - 10
EX6-7 - 15
EX6-7 - 21
EX6-7 - 28
EX6-7 - 36
EX6-7 - 45
EX6-7 - 55
'''


# 연결해주는 메소드 #1
gen5 = itertools.chain('ABCDE', range(1,11,2))
# print('EX6-8 -', list(gen5))
'''
start
continue
end
EX6-8 - ['A', 'B', 'C', 'D', 'E', 1, 3, 5, 7, 9]
'''

# 연결해주는 메소드 #2
gen6 = itertools.chain(enumerate('ABCDE'))
# print('EX6-9 -', list(gen6))
'''
start
continue
end
EX6-9 - [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]
'''

# 개별로 나눠주는 메소드?
gen7 = itertools.product('ABCDE')
# print('EX6-10 -', list(gen7))
'''
start
continue
end
EX6-10 - [('A',), ('B',), ('C',), ('D',), ('E',)]
'''

# 연산
gen8 = itertools.product('ABCDE',repeat=2)
# print('EX6-11 -', list(gen8))
'''
start
continue
end
EX6-11 - 
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), 
('B', 'A'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('B', 'E'), 
('C', 'A'), ('C', 'B'), ('C', 'C'), ('C', 'D'), ('C', 'E'), 
('D', 'A'), ('D', 'B'), ('D', 'C'), ('D', 'D'), ('D', 'E'), 
('E', 'A'), ('E', 'B'), ('E', 'C'), ('E', 'D'), ('E', 'E')]
'''



# 그룹화!
# 이 메소드 매우 좋음!!!
gen9 = itertools.groupby('AAABBCCCCDDEEE')
# print('EX6-12 -', list(gen9))
'''
start
continue
end
EX6-12 - 
[('A', <itertools._grouper object at 0x102d8e240>), 
('B', <itertools._grouper object at 0x102d8e160>), 
('C', <itertools._grouper object at 0x102d8e1d0>), 
('D', <itertools._grouper object at 0x102d8e208>), 
('E', <itertools._grouper object at 0x102d88eb8>)]
'''

for chr, group in gen9:
    # print('EX6-12 -', chr, ' : ', list(group))
    pass

'''
start
continue
end
EX6-12 - A  :  ['A', 'A', 'A']
EX6-12 - B  :  ['B', 'B']
EX6-12 - C  :  ['C', 'C', 'C', 'C']
EX6-12 - D  :  ['D', 'D']
EX6-12 - E  :  ['E', 'E', 'E']
'''

3. 느낀 점

profile
#의식의흐름 #순간순간 #생각의스냅샷

0개의 댓글