운영체제 2: 멀티 프로세스와 멀티 스레드 뜻, 정의, 개념

멀티 프로세스와 멀티 스레드

이번 글에서는 동시성 프로그래밍에서 꼭 필요한 운영체제 개념인 멀티 프로세스와 멀티 스레드 (Multi-Process & Multi-Thread) 에 대해 이해하고, 크롬 브라우저와 파이썬 GIL (Global Interpreter Lock)의 예시를 통해 스레드 안전의 개념까지 알아보겠습니다.

 

멀티 프로세스 (Multi-Process) 와 멀티 스레드 (Multi-Thread)

멀티 프로세스 (Multi-Process)

멀티 프로세스 (Multi-Process)은 하나의 CPU 에서 여러 프로세스를 동시에 수행하는 것을 말합니다. 이는 CPU 에서 수행해야 하는 작업이 많을 때 사용하면 좋습니다.

멀티 프로세싱의 장점과 단점은 다음과 같습니다.

장점:

  • 동기화 문제가 생기지 않습니다. (메모리를 공유하지 않기 때문)
  • 하나의 프로세스에 문제가 발생했을 때, 해당 프로세스만 죽는 것으로 끝납니다. (즉, 영향이 확산되지 않습니다.)

단점:

  • 컨텍스트 스위칭 (context switching) 오버헤드가 큽니다.
  • 프로세스간 자원 공유가 없기 때문에 프로세스간 통신 기법 (Inter-Process Communication, IPC) 을 사용해야 합니다.
    • IPC 의 예시는 Message Passing, Shared Memory 가 있습니다.

 

멀티 스레드 (Multi-Thread)

멀티 스레드 (Multi-Thread) 은 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것을 지칭합니다. 이는 I/O 요청이 많을 때 사용하면 좋습니다.

멀티 스레딩의 장점과 단점은 다음과 같습니다.

장점:

  • 시스템 자원 소모량이 적습니다. (메모리를 공유하기 때문)
  • context switching 오버헤드가 작습니다. 따라서, 작업 처리 속도가 빠릅니다.
  • 스레드는 모든 메모리를 공유하기 때문에 스레드간 통신 (Inter-Thread Communication, ITC)의 부담이 적습니다.
    • ITC의 예시는 Shared Memory, Handler 가 있습니다.

단점:

  • 스레드는 자원 공유를 하기 때문에 병목 현상 (bottleneck) 혹은 데드락 (deadlock) 과 같은 동기화 문제 (synchronization) 가 생길 수 있습니다.
    • 이를 해결하기 위해서 뮤텍스 (mutex lock) 나 세마포어 (semaphore) 를 활용해야 합니다.
  • 하나의 스레드에 문제가 발생하면, 그 스레드를 포함하는 프로세스 전체에 영향을 미칩니다.
  • 프로세스 밖에서 스레드를 제어할 수 없습니다. 다른 프로세스에서 스레드를 제어할 수 없습니다.

 

– 구글 크롬 (Chrome) 은 멀티 프로세스인가, 멀티 스레드인가?

멀티 프로세스
크롬 브라우저는 멀티 프로세싱을 통하여 멀티 탭 기능을 제공합니다. 이 각각의 탭은 하나의 프로세스 입니다.

 

구글 크롬 (Chrome) 은 각각의 탭마다 Process ID (PID) 를 가지고 있으니, 크롬 브라우저는 “멀티 프로세스” 라고 할 수 있습니다. 이 때, 각각의 탭은 “프로세스” 입니다.

크롬 브라우저는 각각의 탭 (tab) 마다 랜더링 정보나 기타 데이터를 별도로 관리하는 등 멀티 프로세스의 특징을 잘 활용하고 있습니다. 그로 인해 메모리를 많이 사용한다는 단점도 있지만, 하나의 탭에 오류가 생겼다고 해도 다른 탭에 영향을 끼치지 않는다는 장점이 있습니다.

 

스레드 안전(Thread-Safety)

스레드 안전 (Thread-Safety) 은 멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없는 것을 말합니다.

즉, 하나의 함수가 한 스레드로부터 호출되어 실행 중일 때, 다른 스레드가 그 함수를 호출하여 동시에 함께 실행되더라도 각 스레드에서의 함수의 수행 결과가 올바르게 나오는 것을 말합니다.

‘Thread-safe하다’ 라는 의미는 두 개 이상의 스레드가 race condition에 들어가거나 같은 객체에 동시에 접근해도 연산 결과는 정합성이 보장될 수 있게 메모리 가시성이 확보된 상태이다.

스레드 안전 여부를 확인하는 법

  1. 전역 변수나 힙, 파일과 같이 여러 스레드가 동시에 접근할 수 있는 자원을 사용하는가?
  2. 핸들과 포인터를 통한 데이터의 간접 접근이 가능한가?
  3. 부수 효과를 가져오는 코드가 있는가?

 

스레드 안전을 지키는 법: 상호 배제 (Mutual Exclusion)

상호 배제 (Mutual Exclusion) 은 한 프로세스가 임계 구역 (critical section) 에 들어가면, 다른 프로세스는 critical section에 들어갈 수 없는 상태를 지칭합니다. 여기서 임계 구역 (critical section) 둘 이상의 프로세스/스레드가 공유 자원에 접근할 때, 순서 등의 이유로 결과가 달라질 수 있는 코드 영역을 말합니다.

상호 배제에서는 임계 구역 (critical section) 을 확인하고 뮤텍스 (mutex lock) 나 세마포어 (semaphore) 로 스레드의 접근을 관리한다.

 

– 파이썬 (Python) 의 스레드 안전

파이썬 (Python) 은 스레드 안전을 보장하지 않는 언어로 알려져 있습니다. 이는, 파이썬 (Python)  은 thread safe 하게 메모리를 관리하지 않기 때문입니다. 그래서 파이썬은 GIL (Global Interpreter Lock)을 통해 스레드 안전을 보장하고 있습니다.

python-gil
파이썬의 GIL (Global Interpreter Lock) 은 위와 같이 작동합니다. (이미지 출처: https://ssungkang.tistory.com/entry/python-GIL-Global-interpreter-Lock%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C)

 

위 그림에서 처럼, 파이썬의 스레드는 GIL (threading.lock) 을 획득 (acquire) 해야지만 공유 데이터에 접근할 수 있습니다. 그리고 스레드는 GIL (threading.lock) 을 해제 (release) 해야지 다른 스레드가 그 lock 을 획득하여 공유 데이터에 접근할 수 있습니다.

위처럼 파이썬은 멀티 스레드 구조이기는 하지만, 스레드가 동시에 instruction 을 수행하지 않고 있습니다. 즉, 파이썬은 구조상 스레드 안전을 보장하기 위하여 멀티 스레드라고 하더라도, 싱글 스레드처럼 작동한다는 특징이 있습니다.

파이썬으로 코드를 작성하는 개발자라면, 위와 같은 파이썬 GIL 의 특성을 잘 이해하는 것이 중요합니다. 그래서 많은 회사의 기술 면접에서 다루는 주제이기도 합니다. 파이썬의 GIL 의 배경을 잘 이해하고 더 나은 코드를 작성하기를 바랍니다.

 

함께 읽으면 좋은 글

 

Reference

Leave a Comment