Context Switch: 프로세스, 스레드 및 오버헤드 이해하기

소개

컴퓨팅 세계에서 효율성과 멀티태스킹은 매우 중요합니다. 현대 운영 체제는 컨텍스트 스위칭이라는 기본 개념 덕분에 여러 애플리케이션이 동시에 실행되는 것처럼 보이게 합니다. 이 글에서는 컨텍스트 스위칭이 무엇인지, 왜 필요한지, 그리고 CPU / OS가 이를 어떻게 관리하는지에 대해 자세히 알아보겠습니다. 또한 프로세스, 스레드 및 경량 스레드 간의 차이점을 탐구하고, 그들의 컨텍스트 스위칭 오버헤드를 비교해보겠습니다.


컨텍스트 스위칭이란 무엇이며 왜 필요한가?

컨텍스트 스위칭의 정의

컨텍스트 스위칭은 CPU가 한 프로세스나 스레드의 실행을 중단하고 다른 프로세스나 스레드로 전환하는 과정입니다. 이는 현재 실행 중인 프로세스나 스레드의 상태(컨텍스트)를 저장하여 나중에 재개할 수 있도록 하고, 다음에 실행할 프로세스나 스레드의 저장된 상태를 로드하는 것을 포함합니다.

image.png

컨텍스트 스위칭의 필요성

컨텍스트 스위칭이 없다면, 하나의 프로세스가 CPU 자원을 모두 소비하여 시스템이 응답하지 않거나 사용자 경험이 저하될 수 있습니다.


CPU / OS가 컨텍스트 스위칭을 관리하는 방법

CPU / OS 상태의 저장 및 복원

컨텍스트 스위칭이 발생할 때, CPU는 다음을 수행해야 합니다:

  1. 현재 상태 저장: 모든 CPU 레지스터의 값, 프로그램 카운터 및 스택 포인터를 프로세스의 제어 블록에 저장합니다.
  2. 프로세스 제어 블록(PCB) 업데이트: PCB는 프로세스를 나중에 재개하는 데 필요한 모든 정보를 보유합니다.

    image.png

  3. 다음 프로세스나 스레드 선택: 스케줄러는 스케줄링 알고리즘에 따라 다음에 실행할 프로세스나 스레드를 결정합니다.

  4. 새 상태 로드: 선택된 프로세스나 스레드의 저장된 상태를 PCB에서 복원합니다.

컨텍스트 스위칭에 관련된 구성 요소

컨텍스트 스위칭 시 메모리 관리

image.png

인터럽트와 트랩

컨텍스트 스위칭은 종종 다음에 의해 트리거됩니다:

인터럽트가 발생하면 CPU는:

  1. 현재 컨텍스트를 저장합니다.
  2. 인터럽트 핸들러를 실행합니다.
  3. 스케줄링 정책에 따라 컨텍스트 스위칭 여부를 결정합니다.

프로세스, 스레드 및 경량 스레드

프로세스

image.png

스레드

경량 스레드

image.png


컨텍스트 스위칭 오버헤드 비교

프로세스

스레드

경량 스레드

시각적 비교

항목 프로세스 스레드 경량 스레드
메모리 공간 전환 아니오 아니오
커널 개입 아니오
컨텍스트 스위칭 오버헤드 높음 중간 낮음
스케줄링 커널 수준 커널 수준 사용자 수준
동기화 복잡한 IPC 동기화 프리미티브 사용자 수준 동기화

애플리케이션 설계를 위한 시사점

컨텍스트 스위칭 오버헤드의 차이를 이해하는 것은 효율적인 애플리케이션 설계에 중요합니다:


파이썬에서 컨텍스트 스위칭 최소화 방법

파이썬에서 컨텍스트 스위칭을 최소화하여 애플리케이션의 성능을 향상시킬 수 있습니다. 다음은 파이썬 개발자가 컨텍스트 스위칭을 줄이기 위해 고려할 수 있는 방법들입니다:

1. 비동기 프로그래밍 활용

import asyncio

async def fetch_data():
    # 비동기 I/O 작업 수행
    pass

async def main():
    tasks = [fetch_data() for _ in range(10)]
    await asyncio.gather(*tasks)

asyncio.run(main())

2. 멀티스레딩 대신 멀티프로세싱 사용

from multiprocessing import Pool

def compute():
    # CPU 집약적인 작업 수행
    pass

if __name__ == '__main__':
    with Pool(4) as p:
        p.map(compute, range(10))

3. 스레드 수 최소화 및 재사용

from concurrent.futures import ThreadPoolExecutor

def task():
    # I/O 바운드 작업 수행
    pass

with ThreadPoolExecutor(max_workers=5) as executor:
    for _ in range(10):
        executor.submit(task)

4. 작업 병합 및 일괄 처리

5. 적절한 동시성 모델 선택

6. C 확장 모듈 사용 고려

# cython: language_level=3
def compute():
    cdef int i
    for i in range(1000000):
        pass

7. CPU 어피니티(CPU Affinity)를 활용한 컨텍스트 스위칭 최소화

image.png

import os

def compute():
    # CPU 집약적인 작업 수행
    pass

if __name__ == '__main__':
    cpu_id = 0  # 바인딩할 CPU 코어 ID
    pid = os.getpid()
    os.sched_setaffinity(pid, {cpu_id})
    compute()

결론

컨텍스트 스위칭은 현대 운영 체제에서 멀티태스킹을 가능하게 하는 기본 메커니즘입니다. CPU가 컨텍스트 스위칭을 어떻게 관리하는지, 그리고 프로세스, 스레드, 경량 스레드 간의 차이를 이해함으로써 개발자는 애플리케이션 성능을 최적화하기 위한 현명한 결정을 내릴 수 있습니다.

적절한 병행성 모델을 선택하는 것은 애플리케이션의 성능 요구 사항, 리소스 제약 조건 및 관리할 복잡성에 따라 달라집니다.