프로세스와 스레드

박지은·2023년 4월 12일
0

프로세스란?

프로세스는 운영체제에서 실행 중인 프로그램 입니다.
운영체제는 프로세스의 실행에 필요한 시스템 자원을 할당 및 관리하며, 실행 상태를 제어합니다.

그렇다면 프로세스는 어떻게 구성되어 있을까요?
프로세스는 4가지 섹션으로 구성되어 있습니다.

  • 코드: 프로그램 코드를 구성하는 명령어들의 집합
  • 데이터: 프로그램에서 사용되는 전역 변수, 정적 변수 등
  • 스택: 지역 변수, 매개 변수 등
  • 힙: 동적 할당 된 메모리 저장

각 섹션은 서로 다른 권한을 가지며, 메모리에서 서로 다른 위치에 저장됩니다.
또한 프로세스가 메모리를 공유하지 않으며, 각각의 프로세스가 독립적으로 실행됩니다.

스레드란?

프로세스 내 실행되는 흐름의 단위 입니다. 스레드를 이용할 경우 하나의 프로세스내 여러 부분을 동시에 실행 가능합니다.

스레드는 다음과 같이 구성되어 있습니다.

  • 독립적 부분: 스택, 레지스터, 프로그램 카운터
  • 공유하는 부분: 힙, 데이터, 코드 영역

따라서 스레드들은 자원을 공유한 채 실행에 필요한 최소한의 정보만으로 실행됩니다.

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

프로세스와 스레드 여러개가 동시에 실행되는 것을 각각 멀티 프로세스, 멀티 스레드라고 합니다.

멀티 프로세스

멀티 프로세스는 동시에 여러개의 프로세스가 실행되는 것입니다. 이를 위해 운영체제는 프로세스들이 독립적으로 실행될 수 있도록, 각 프로세스마다 자원을 할당하고, 프로세스 간 통신을 위한 IPC 기법 등을 제공합니다.

장단점에는 무엇이 있을까요?

장점

  • 각 프로세스가 영향 없이 독립적으로 실행되기 때문에, 안정성이 높아짐
  • 메시지를 보내는 방식으로 통신하, 경쟁 상태나 데드락 등의 문제를 방지

단점

  • 각 프로세스는 자신만의 메모리 공간을 할당받아 자원 소모가 큼
  • IPC기법 등의 경우 오버헤드가 커서 성능 저하 초래
  • 프로세스 간 데이터 공유 시 동기화 문제도 발생 가능

IPC??
프로세스간 통신 방법에는 크게 2가지가 있습니다.

  1. 공유 메모리
    프로세스들이 공유하는 메모리 영역을 만들어 데이터를 주고 받는 방식입니다. 이때 동기화 기법을 이용하여 데이터의 일관성을 유지합니다.
  2. 메시지 패싱
    프로세스 간에 메시지를 주고 받는 방식입니다. 이를 위해 운영체제가 제공하는 메시지 큐 혹은 파이프를 이용합니다. 데이터를 복사하여 전달하여 안정성은 높으나 오버헤드가 발생할 수 있습니다.

멀티 스레드

멀티 스레드는 하나의 프로세스 내에서 여러 개의 스레드를 생성하고, 각 스레드가 독립적으로 작업을 수행하는 것 입니다.

각 스레드는 프로세스 내 공유 메모리를 이용해 서로 통신하며, 스레드 간 문맥 전환이 빨라 프로세스 간 전환에 비해 빠른 작업 수행이 가능합니다. 따라서 자원과 시스템이 효율성이 증가합니다.

장점

  • 공유메모리를 이용하여, 자원 절약 가능
  • 멀티 프로세스 방법에 비해 문맥 전환이 빠름

단점

  • 여러 스레드가 공유하는 자원에 동시 접근하여 데이터의 일관성이 깨질 수 있음
  • 하나의 스레드에 문제가 발생할 경우 자원을 공유하는 다른 스레드에도 영향을 끼침
  • 여러 스레드가 동시에 실행되기 때문에 문제 발생 시 어느 스레드의 문제인지 추적이 어려움

동기화

동기화란,
여러 프로세스 혹은 스레드 간에 작업을 조율하는 것 입니다.

멀티 프로세스와 멀티 스레드 환경에서 공유 자원이 이용되는 것을 확인할 수 있었습니다. 이때, 데이터의 무결성을 보장하고 작업이 올바른 순서로 실행하기 위하여 동기화를 이용합니다.

먼저 공유 자원이 무엇일까요?

  • 공유 자원: 여러 개체 또는 프로세스 또는 스레드에서 공동으로 사용하는 자원
  • 임계 구역(Critical section): 공유 자원을 동시에 접근하거나 수정하는 코드 구역

이 임계구역에 하나의 프로세스혹은 스레드만 접근하도록 하기 위해 동기화 기법을 이용합니다.

  1. 뮤텍스
  • 상호 배제를 구현하기 위한 동기화 기법입니다.
  • 구성
    • 전역 변수 lock: 자물쇠 역할
    • acquire(): 임계 구역을 잠그는 역할
    • release(): 임계 구역의 잠금 해제 역할
  • 뮤텍스를 사용하는 스레드는 먼저 임계 구역을 잠그고 작업을 수행한 후, 잠금 해제를 해 다른 스레드가 이용할 수 있도록 합니다.
  1. 세마포어
  • 프로세스나 스레드 사이에서 공유된 자원에 대한 접근을 제어합니다.

  • 구성
    - 전역 변수 S: 임계 구역에 진입할 수 있는 프로세스의 개수
    - wait(): 임계 구역에 들어가도 좋은 지, 기다려야 하는지 알려줌
    - signal(): 임계 구역 앞에서 기다리는 프로세스에 '이제 가도 좋다'고 신호를 줌

    각 프로세스가 wait함수 호출해 S의 값을 확인해 0이 아닐경우 S값을 1빼고 임계 구역에 진입 하고, 끝나면 임계 구역을 빠져나와 signal 함수 호출해 다시 S의 값을 1 더합니다. 이후 업데이트 된 S 값 기준으로 대기하던 다른 프로세스가 임계 구역에 진입합니다.
  • 만약 세마포어에서 실행 순서를 제어하려면,
    먼저 실행될 프로세스 뒤에 wait 함수 뒤에 실행될 프로세스 앞에 signal함수를 두어 앞의 프로세스가 끝나야만 뒤의 프로세스가 임계 구역에 접근할 수 있도록 합니다.

  1. 모니터
  • 공유 자원과 공유 자원에 접근하기 위한 인터페이스를 묶어서 관리합니다.
  • 프로세스는 반드시 인터페이스를 통해서만 공유자원에 접근 합니다.
  • 공유 자원에 접근하고자 하는 프로세스틑 큐에 삽입되며, 순서대로 하나씩 접근 가능합니다.
  • 실행 순서를 제어하려면,
    조건 변수를 이용합니다. 따라서 순서가 되어 접근한 프로세스라도 실행 조건이 만족되지 못할 경우 조건 변수가 가지고 있는 큐에서 대기하게 됩니다.

파이썬에서의 멀티스레드

파이썬에서도 멀티스레드 방식을 이용할 수 있습니다.
그런데, 실제로 위에서 작성했던 피보나치 함수를 멀티스레드로 실행할 경우 시간이 빨라지지 않는 것을 확인할 수 있습니다.

멀티스레딩 X멀티 스레딩 O
0.000070.00085
# 1 Thread
start_time = time.time()
fibonacci(10)
fibonacci(10)
end_time = time.time()
print(f'{end_time-start_time:.5f}')

# 2 Thread
start_time = time.time()
threads=[]
for i in range(2):
    threads.append(threading.Thread(target=fibonacci, args=(10,)))
    threads[-1].start()
for t in threads:
    t.join()
end_time = time.time()
print(f'{end_time-start_time:.5f}')

파이썬은 기본적으로 한번에 하나의 스레드만 동작 가능 합니다. 파이썬에서는 스레드를 이용한 병렬 처리를 지원하지만, GIL로 인해 여러 스레드가 동시에 실행되지는 않습니다.

그러면 이쯤에서...

동시성과 병렬성

둘 다 겉으로 보기에는 동시에 동작한다는 말인것 같으나, 실제 동작에는 차이가 있습니다.

  1. 동시성
    : 동시에 실행될 수 있는 여러 작업이 하나의 프로세스에서 번갈아가면서 실행되는 것입니다. 각 작업은 일정 시간 간격으로 실행되기 때문에, 마치 동시에 실행되는 것처럼 보입니다.
    ex) 하나의 CPU에서 여러 프로세스들이 번갈아가면서 수행

  2. 병렬성
    : 동시에 실행될 수 있는 여러 작업이 여러 개의 프로세서에서 동시에 실행되는 것입니다. 각 작업이 서로 독립적으로 실행되므로, 전체 작업의 속도가 오릅니다.
    ex) 멀티코어 CPU에서 각 코어당 하나의 스레드가 배정되어 동시에 작동

GIL?

GIL(Global Interpreter Lock)은 파이썬 인터프리터에서 사용되는 동시성 모델 중 하나입니다.

  • 파이썬 인터프리터에서 파이썬 객체에 대한 접근을 조율하기 위한 메커니즘입니다.
  • 파이썬 객체는 모든 스레드가 접근할 수 있는 공유 자원이기 때문에
    -> GIL은 이를 보호하기 위해 하나의 스레드만이 파이썬 객체에 접근할 수 있도록 합니다.
  • 따라서, 파이썬에서 멀티 스레드를 이용한 병렬 처리가 실제로는 병렬이 아니라 동시성이 됩니다.

그렇다면 python에서는 여러 스레드를 이용해 성능을 개선하는 방법은 없는 걸까요?

CPU bound작업의 경우, 그렇습니다.
하지만 I/O bound작업을 할 경우에는 여러 스레드를 이용해 동시에 I/O작업을 처리하는 것이 가능합니다.

CPU bound 작업의 동작

각 스레드는 CPU에서 동시에 실행되지 않고 번갈아가면서 동작됩니다.
따라서 멀티 스레드를 이용한다고 하여 성능의 향상은 없습니다.

I/O bound 작업의 동작

외부 호출을 하는 I/O bound 작업의 경우 외부 호출을 하기 위해 시스템 콜을 호출하는 동안은 병렬로 작업이 불가능하나 외부에서의 동작은 병렬로 진행될 수도 있습니다.
그렇기 때문에, I/O bound 작업에서는 성능의 향상을 기대해 볼 수 있습니다.

profile
Today I learned...

0개의 댓글