콘텐츠로 건너뛰기
Home » coroutine

coroutine

asyncio – 일반 함수를 비동기로 사용하기

지난 글에서 urlopen()과 같은 표준 라이브러리 함수를 어떻게 비동기 코루틴처럼 asyncio에서 사용할 수 있는지 살펴보았다. aiohttp 등의 비동기 라이브러리를 사용해서 여러 핸들러를 작성해야 할 때, 이와 같은 처리를 많이 해야 한다면 빈번하게 런루프 메소드를 호출하는 것보다, 간단히 데코레이터를 만들어서 활용하는 것이 어떨까? asyncio의 이벤트 루프에는 run_in_executor(executor, fn, *args) 가 있다. 이 메소드는 concurrent.futures 모듈의 ThreadPoolExecutor나 ProcessPoolExecutor를 사용하여 일반적인 blocking 함수를 다른 스레드 및 프로세스에서 실행하도록 하고 그 자신은 처리를 기다리는 코루틴을 생성한다. 이 기능을 사용하면 일반적인 blocking-I/O 함수를 non-blocking 함수처럼… 더 보기 »asyncio – 일반 함수를 비동기로 사용하기

파이썬 yield from – 다른 제너레이터에게 위임하기

파이썬에서는 어떤 함수 내부에 yield 키워드가 사용됐다면, 이 함수를 무조건 제너레이터 함수로 본다. 제너레이터 함수는 제너레이터를 만드는 함수이고, 다시 제너레이터는 어떤 값을 필요한 만큼 반복적으로 만들어내는 객체이다. 제너레이터는 일반 함수와 비슷하게 생겼지만, 함수가 return 구문을 만나면 실행이 끝나버리는데 비해, 제너레이터는 yield 구문에서 값을 외부로 내보낸 후 “일시정지” 상태가 되었다가 필요할 때 다시 실행 흐름을 이어나갈 수 있다. 필요에 따라서는 일시 정지한 제너레이터를 다시 깨울 때 값을 내부로 전달할 수 있는데, 이런 특징을 활용하면 함수를 띄워놓고 필요한 시점에 반복적으로 값을 집어넣었다가… 더 보기 »파이썬 yield from – 다른 제너레이터에게 위임하기

파이썬의 제너레이터와 코루틴

파이썬 제너레이터는 특별한 종류의 함수 객체이다. 함수 내부에서 yield 구문을 사용하여 특정 값을 내놓은 후에도 실행을 종료하지 않아 제거되지 않고, 다시 그 자리에서부터 이어서 계산을 반복하고 다시 값을 내놓을 수 있다. rangemap, filter 등의 객체가 제너레이터의 일종이라고 할 수 있다.

아주 먼 옛날, 파이썬 2.5에서 제너레이터에 특별한 기능이 생겼는데, 바로 제너레이터 속으로 값을 전달하는 기능이다. (PEP342) 이는 매우 흥미로운 패턴으로 이어지게 되는데, 실행 중 한 번 yield 문을 만나 자신의 위치를 기억하고 있다가 다시 그 자리에서 실행이 가능하다는 점에서 두 개 이상의 제너레이터가 서로 값을 주고 받으면서 교차식으로 실행하는 것이 가능하다. 이는 일반적인 함수 호출의 패턴인 주 루틴 – 서브 루틴의 관계와 달리 두 개의 루틴이 함께 실행된다는 부분에서 코루틴(coroutine)이라고 부른다.

코루틴은 사실 완전히 새롭게 등장한 개념은 아니었다. 이미 6~70년대에 기반이 닦여진 기술이이었다. 당시에는 작업 흐름의 분산을 위한 여러 가지 개념들이 도입되고 시도되고 있었는데, 이 당시에 이러한 기술들 중에서 가장 환호를 받았던 것은 다름 아닌 멀티스레드였다.

멀티스레드가 큰 인기를 얻고 발전해 나가면서 상대적으로 코루틴은 거의 방치되다 시피하였으나, 규모가 커짐에 따라 멀티 스레드는 자원 경쟁이라든지 동기화문제 등 더 큰 골칫거리를 가져왔다. 이러한 문제로 인해 코루틴 개념은 그린릿(greenlet)이나 경량스레드(lightweight thread)라는 이름으로 재발견되어 주목받는 경우도 있다.

코루틴이 흥미로운 지점은 멀티스레드 없이 하나의 스레드 위에 여러 개의 실행흐름이 존재할 수 있다는 것이다. 즉 멀티스레드에서의 골치 아픈 문제들을 끌어들이지 않고서도 실행 흐름을 분산할 수 있다는 것을 의미한다.

하지만 분산처리와 같은 상황이 아니더라도 제너레이터 혹은 코루틴은 파이썬 프로그래밍에서 매우 중요한 비중을 차지한다. 멀티스레드와 같은 적극적인 동시성이 아니더라도, 제너레이터의 ‘느긋한(lazy)’한 특성은 실제로는 concurrent 하지 않은 작업들을 마치 동시에 진행되는 것처럼 다룰 수 있게 하며, 무거운 연산을 가능한 뒤로 미루어 실행 시간내의 체감 퍼포먼스가 좋은 것처럼 보일 수 있게 한다. (사실 이정도면 충분한 것이, 파이썬의 멀티스레드는 실제로는 동시에 실행되지 않기 때문이다.)

이 외에도 제너레이터와 코루틴은 간단한 클래스를 대체할 수 있으며, 일련의 처리 과정에서의 단위 작업을 구성하고 이들을 선언적으로 연결하는 방법으로도 활용할 수 있다. 오늘 이 글에서는 제너레이터와 코루틴에 대해 알아보도록 하자.

더 보기 »파이썬의 제너레이터와 코루틴