Victoree's Blog

[6] 제어흐름 - 코루틴 본문

Python/Fluent Python

[6] 제어흐름 - 코루틴

victoree 2023. 6. 22. 18:53
728x90

코루틴을 알아가기 전에, 예에전에 대학시절에 공부했던 프로세스와 스레드와 관련한 내용을 잠시 잠깐 리뷰하고 가자.

6.1 프로세스와 스레드

Process는 실행중인 프로그램을 말하며, 최소 1개의 thread로 구성되고 thread 단위로 스케줄링된다. 프로세스는 create, ready, run(cpu나 메모리같은 자원을 받음), suspension (메모리를 뺏김) ..등등의 다양한 상태값을 가지며 process control block에 해당 정보(pid, state, program counter - 다음으로 실행할 명령어)들이 기록된다.  stack, heap, text(code), data 네개의 자원을 할당받는다.
프로세스 같은 경우, 각 자원들을 독립적으로 할당받기 때문에 종료되어도 다른 프로세스에 영향을 미치지 않지만 그만큼 자원이 많이 필요하고 타 프로세스와 데이터를 공유하려면 별도의 통신이 필요하다.

Thread는 프로세스 내에서 실행되는 흐름의 단위로 테스크라고 생각하면 된다. 둘 이상의 thread가 실행되는 것을 multi thread 환경이라고 말하며, 프로세스 작업의 주체이다. thread의 경우, 프로세스와 다르게 스택만 할당받고 그 외의 자원은 공유하게 된다. 그렇기 때문에 시스템 자원과 처리비용은 낮지만, 같은 자원 접근 시 동기화 문제가 있고 test나 디버깅이 어렵다. 또한 멀티스레드 환경에서는 context switching 비용이 들게 된다. 

 

6.2 코루틴

코루틴은 파이썬에서 동시성 프로그래밍을 지원하는데에 있어, 중요한 개념이다. 코루틴은 generator에서 진화한 개념인데, yield 키워드를 표현식에서 사용할 수 있게 되었고, send() 메소드가 제너레이터 API에 추가되면서 제너레이터의 호출자가 제너레이터 함수 내부의 yield 표현식의 값이 될 데이터를 전송하게 될 수 있었다. 제너레이터 안에서 yield 표현식의 값은 외부 코드에서 제너레이터의 send 메서드에 전달한 값이다. 

이를 통해 제너레이터가 호출자에 데이터를 생성해주고, 데이터를 받아오면서 호출자와 협업하는 코루틴이 되었다. 

코루틴은 4가지의 상태를 가진다. 

  • gen_created : 실행 시작을 위해 대기하는 상태
  • gen_running : 인터프리터가 실행중
  • gen_suspended : yield에서 대기중
  • gen_closed: 완료됨

코루틴을 사용할 때에는 반드시 next()를 호출하여 기동시켜 놓아야하며, 우리는 @coroutine 이라는 자동 기동 데코레이터를 통해 기동시킬 수 있다. 

6.3 GIL == Global Interpreter Lock

GIL은 Cpython에서 돌아가는 interpreter lock으로, 프로세스 당 한번에 하나의 기본 스레드만 실행되도록 동작한다. 그래서 동작이 거의 싱글 스레드라고 보면 된다. 파이썬은 reference counting 방식으로 사용되는 자원의 메모리를 관리하는데, 여러 스레드가 동시에 해당 자원을 이용하다 refcount를 수정하려고 할때 에러가 발생할 수 있어서 전역에 lock을 걸어 동시 접근을 제한한다. 

IO 작업을 할 때는 GIL 해제되기 때문에, 다른 작업이 가능해져 성능이 나쁘다고만 할수없다. GIL 방식을 원하지 않는 경우, Jython이나 PyPy를 사용하는 방법이 있다. 

 

728x90
Comments