Dev

Python의 asyncio를 직접 만들어보자 (1)

October 16, 2018

Python의 asyncio를 직접 만들어보자 (1)

이 포스트 시리즈는 김준기님의 Pycon KR 2018의 튜토리얼 세션을 복습하기 위해 작성되었습니다.

Python의 asyncio 패키지는 싱글 쓰레드 환경에서 매끄러운 동시성 구현을 위해 3.5 버전부터 추가되었다. 파이썬의 제네레이터를 이용해 asyncio의 기능을 직접 구현해 보면서 원리를 간단히 이해해 보자!

동시성 (Concurrency)

(사용자 입장에서) 동시에 두 개 이상의 작업이 실행되고 있다고 느낄 수 있도록 만드는 것

멀티 쓰레드에서의 동시성 구현

장점

머신에 가깝기 때문에 폭 넓은 시스템에서 적용이 가능하고 대부분의 프로그래밍 언어와 통합되어 있다.

단점 1 Deadlock

둘 이상의 쓰레드가 서로 뮤텍스를 얻으려고 무한히 기다리는 상태

  • 런타임이나 가상머신을 통째로 종료하거나,
  • 데드락에 걸린 쓰레드만 시그널 혹은 타임아웃으로 죽이거나,

하는 방법으로 해결은 가능하지만 의도된 동작이 아니므로 데드락이 발생하지 않도록 신경을 써야 한다.

단점 2 Race Condition과 Memory Visibility

둘 이상의 쓰레드가 동시에 같은 공유 메모리를 수정하려고 시도하거나(경쟁 조건), 하나의 쓰레드가 수정한 연산이 아직 CPU 캐시에서 메인 메모리로 플러시 되지 않은 경우, 다른 쓰레드가 오래된 값을 읽어갈 수 있다(메모리 가시성).

기타 단점

  • 비싼 쓰레드 생성 비용
  • 안정적인 애플리케이션 운영을 위해 쓰레드 풀 관리 필요
  • 힘든 디버깅과 테스트
  • 뮤텍스의 범위에 따른 안전성과 효율성의 저울질

싱글 쓰레드에서의 동시성 구현

Javascript의 이벤트 모델

Javascript의 V8 엔진은 논블록-비동기 모델을 통해 동시성을 구현한다.

12:50, 15:30을 보자.

콜백 패턴

위의 동시성 모델 구현을 위해서 Javascript는 콜백 패턴을 적극적으로 활용하고 있다. 그러나 콜백 패턴은 다음과 같은 잘 알려진 문제점들이 있다.

못생김

위험함

  • you may get duplicate callbacks
  • you may not get a callback at all (lost in limbo)
  • you may get out-of-band errors
  • emitters may get multiple “error” events
  • missing “error” events sends everything to hell
  • often unsure what requires “error” handlers
  • “error” handlers are very verbose
  • callbacks suck

TJ Holowaychuk의 에서 발췌

대안은?

위의 [Farewell Node.js]에 이런 댓글이…?

Iyobo Eki

IMO Generators should have been the core of NodeJS from the get go before someone decided to put javascript on the server. Sometimes I wish it were as easy as waving a wand and all useful 3rd party libraries would be instantly generator-ized…but alas, we now have a legacy problem.

TJ Holowaychuk

I completely agree! If v8 would have had async/await back then we could have avoided all kinds of issues from the very beginning. I’ve been ranting about coroutines (and coros in js) for a long time but the majority of people in or around Node’s core were content with callbacks.

그렇다… 답은 제너레이터(코루틴)이었던 것이다…

동시성과 코루틴?

쓰레드나 파이버(Fiber: 비선점형 경량 쓰레드), 그린 쓰레드(Green Thread: 언어 혹은 VM 레벨의 쓰레드)등과는 달리 코루틴은 동시성 프로그래밍 자체가 목적은 아니다. 코루틴은 서브루틴(함수)이나 GOTO문 처럼 제어 흐름에 불과하다.

그렇다면 이런 제너레이터가 왜 코루틴인지, 또 제어 흐름에 불과한 코루틴이 어떻게 동시성 프로그램에서 응용될 수 있을지 알아보자.