728x90

블로그에 스레드와 프로세스 정리한 글

 

이미 프로세스와 스레드의 개념에 대해서 정리한 적이 있다. 

이를 복습하고 다시 정리하면서 회사에서 python으로 작업할 때 pool 모듈을 활용해서 병렬처리를 해주었던 기억이 났다. 

 

pool모듈은 파이썬에서 멀티프로세싱을 통해서 병렬처리를 해주는 것이다. process모듈도 있는데 둘의 차이는

- pool 모듈은 바닥에 여러 작업들 던져놓고 알아서 병렬처리 되도록 한것

- process 모듈은 순서를 지정해주는 것

 

파이썬에서의 pool VS process 사용

 

순간 의문이 든 것이, 프로세스만으로 프로그램 실행에 한계가 있어서 스레드란 개념이 등장한 것인데, 파이썬에서는 왜 빠른 자원 처리를 위해 멀티 스레드가 아니라 프로세스를 몇개 더 구동하는 멀티 프로세스를 사용하는 것일까?

아니면 멀티 스레드를 사용할 수 있지만 멀티 프로세스를 사용하는 이유가 있을까?

 

이에 대한 해답은 파이선 자체의 특징에 있었다.

실제로 파이썬에서 멀티 스레드 실행해 주어도 실행하지 않았을 때와 작업 시간에 차이가 없다. 이는 파이썬의 GIL 정책때문이라고 한다.

 

GIL(Global Interpreter Lock) 

언어에서 자원을 보호하기 위해 락 정책을 사용하는데, 파이썬에서는 하나의 프로세스 안에서 모든 자원의 락을 관리함으로써 한번에 하나의 쓰레드만 자원을 컨트롤하여 동작하도록 하는 것이다. 

그렇다면 파이썬에서는 멀티 쓰레드가 주는 장점을 다 취하지 못하면서 까지 GIL이라는 락 정책을 실행하는 것일까?

메모리 관리에서 핵심은 쓰레드들은 프로세스가 공유하는 메모리에 접근하고 이를 서로 공유할 수 있지만, 여러 개의 프로세스가 동시에 메모리의 같은 위치를 사용하려고 하면 안된다. 여러 쓰레드가 동시에 공유된 데이터에 접근해서 변경하려고 하면 race condition이 발생하고 이러한 상태를 not thread-safe라고 하고, 그렇지 않은 상태를 thread-safe라고 한다. 

즉 파이썬의 메모리 관리 방식이 not thread-safe하기 때문에 멀티 스레드의 cpu 공유를 잠궈 두었을 것이다. 

이는 파이썬이라는 언어 자체의 특성 때문이다. 파이썬에서는 모든 것이 객체이다. 

 

그 모든 객체는PyObject라는 struct타입이다. PyObject는 
 - ob_refcnt: reference count
 - ob_type: pointer to another type
을 가지는데 CPython은 생성되는 객체 PyObject의 reference를 세어가면서(ob_refcnt) 메모리 관리를 한다.
그런데 객체의 reference를 세다가 race condition이 발생한다던지 할 수 있기 때문에 메모리 관리의 필요성이 있다. 이 방식대로라면 not thread-safe하다.. 

해당 블로그 내에서 언급/참고

 

하지만 이러한 락 정책 또한 연산이 많이 필요한 cpu동작에 한해서이고, I/O 작업을 실행하는 동안에는 다른 쓰레드가 cpu동작을 동시에 실행할 수 있다. 

 

즉 파이썬에서 멀티 쓰레드를 사용하지 못하거나 하지 않는 것은 아니고, cpu 동작에서는 병렬처리를 멀티 스레드로 구현할 수 없고, 멀티 프로세스로만 가능하지만(GIL 로 인해) 네트워크 통신과 같은 I/O 동작이 메인인 작업에서느 멀티 스레드만으로 성능상 효과를 구현할 수 있다. 

 

cpu bound VS I/O bound

 

참고 블로그 : 파이썬 GIL

728x90

+ Recent posts