본문 바로가기

Computer Science

Process vs Thread 정리

728x90
기본부터 탄탄히해보자....!!
본 포스팅은 프로세스와 스레드 부터 멀티 프로세스 멀티 스레드에 대해 간단히 정리된 내용을 담고 있다.

프로세스

- 운영체제로부터 자원(CPU 시간, 메모리, 주소 공간 등)을 할당받은 작업의 단위

- 메모리에 올라와 실행되고 있는 프로그램의 인스턴스 (프로그램은 메모리에 올라가 있지 않은 정적인 상태를 뜻한다.)

프로세스의 작동 원리

- 프로세스는 각각 독립된 메모리 영역(Code, Data, Stack, Heap)을 할당 받는다.

    - Code 영역: 프로그램을 실행시키는 실행 파일 내의 명령어 (소스코드). Read Only. 프로세스 종료될 때 까지 유지.

    - Data 영역: global, static, array, structure 저장. 프로세스 종료될 때 까지 유지.

    - Heap 영역: malloc, free 등 동적으로 사용하는 영역

    - Stack 영역: 지역변수, 매개변수 등 프로그램이 사용하는 임시 메모리. 함수 호출 시 생성. 함수 종료시 반환

 

- 프로세스의 가상 메모리

    - 32bit?: 데이터 이동 통로인 I/O 버스가 한번에 전달할 수 있는 데이터의 크기가 32bit. CPU가 한번에 처리할 수 있는 데이터 크기가 32bit.

    - 32bit 시스템에서 메모리 주소 공간을 표현할 수 있는 범위는 2^32 -> 4GB

    - 32bit 시스템에서 프로세스 생성시 최대 4GB메모리 할당

    - 컴퓨터의 메모리에 프로세스 당 4GB 씩 할당 가능......? (프로세스 1000개면 4000GB....??) -> 가상의 주소페이징을 사용한 가상 메모리 공간 사용

    - 가상 메모리에 대한 설명 블로그1

    - 가상 메모리에 대한 설명 블로그2

 

[OS] 가상 메모리

가상 메모리와 이를 활용하기 위한 페이징 시스템에 대해 알아보자

velog.io

 

OS 만들기 #20 가상메모리, 페이징(PAGING) 처리 - 1

개인적인 일과 OS 만드는 과정에서 너무 지식이 부족함을 느끼고.. 한동안 공부만 했다. 이해 안되는 개념은 이해 될때까지 예제와 문서 읽으면서 공부를 하긴 했는데 역시나 OS 만드는 것에 대한

manggong.org

쓰레드

- 한 프로그램을 처리하기 위해 프로세스 여러개를 만들어볼까? -> 쓰레드

- 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위

쓰레드의 작동 원리

- 쓰레드는 프로세스 내의 주소 공간이나 자원을 공유

    - Stack을 제외한 Code, Data, Heap 영역 공유

- 한 쓰레드가 프로세스 자원 변경하면, 다른 Sibling Thread 또한 즉시 확인 가능.

프로세스 vs 쓰레드

최소 작업 단위?

- 프로세스: 운영체제 관점에서 최소 작업 단위

- 쓰레드: CPU 관점에서 최소 작업 단위

따라서 같은 프로세스 내의 쓰레드 끼리는 메모리 공유할 수 밖에..

 

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

- 멀티 프로세싱: 여러개의 프로세스가 하나의 작업 처리

    - 한 프로세스에 문제 발생해도, 다른 프로세스 정상 작동 (자원 공유 안하기 때문에)

    - Context Switching에서의 오버헤드 (캐쉬 메모리 초기화 등 시간 소모 및 자원 손실 발생)

    - IPC(Inter-Process Communication) 사용하여 다른 프로세스 정보 접근 가능

- 멀티 쓰레딩: 하나의 프로세스가 여러개의 쓰레드를 사용하여 하나의 작업 처리

    - 한 쓰레드에 문제 발생할 시 전체에 영향을 줌

    - 시스템 자원 소모 감소

    - 용이한 Context Switching (Stack 영역을 제외한 모든 메모리 공유)

    - Race Condition, Critical Section 고려하여 설계

 

In Python????

- 파이썬에서는 GIL(Global Interpreter Lock) 사용

    - 특정 시점에서 인터프리터를 사용하는 쓰레드는 언제나 1개

    - 한번에 한 쓰레드만 바이트 코드 실행 -> 멀티 쓰레드가 싱글 쓰레드 보다 더 나쁜 성능을 가질수도

    - I/O 작업은 제외 -> CPU 작업이 적고 I/O 작업이 많은 병렬 처리 프로그램에서 효과

    - 자원 관리를 쉽게 구현할 수 있다는 장점도 있음.

 

Examples

import time
from threading import Thread

result = 0

def _work(start, end):
    global result
    for i in range(start, end):
        result = result + i
    print(result)

def _not_using_thread(start, end):
    _work(start, end)

def _using_thread(start, end):
    th1 = Thread(target=_work, args=(start, end//2))
    th2 = Thread(target=_work, args=(end//2, end))

    th1.start()
    th2.start()
    
    th1.join()
    th2.join()

if __name__ == "__main__":
    start = 0
    end = 10000000
    
    started = time.time()
    _not_using_thread(start, end)
    print("[+] time for not using thread is {}".format(time.time() - started))

    result = 0
    started = time.time()
    _using_thread(start, end)
    print("[+] time for using thread is {}".format(time.time() - started))

 위 예제는 0부터 10000000까지 더하는 파이썬 코드이다. 우선 thread를 사용하지 않고(_not_using_thread) 실행을 한다. 그리고 thread를 사용하여(_using_thread) 반반씩 global 변수인 result에 더한다.

 

결과를 예측해보면 두개의 쓰레드가 동시에 돌아가는 두번째 함수가 더 빠를 것 같지만 실제 결과는 다르다. result가 실제답과 다르며, 시간 또한 쓰레드 없는 함수보다 느리다.

 

우선 result의 값이 다른 이유는 Race Condition이 일어나서 생기는 이슈이다. result라는 global 변수에 두 쓰레드가 동시에 접근했기 때문이다. 마지막으로 시간이 더 느린 이유는 GIL 때문이다. 인터프리터를 잠그기 때문에 실제로 돌아가는 쓰레드는 항상 하나이다.

 

Result에 Race Condition이 일어난 결과가 의문스러웠다. GIL로 인해 result가 잠금 설정되지 않았을까? 이에 조사해본 결과, GIL로 인해 파이썬 쓰레드가 한 번에 하나만 실행되지만, 파이썬 인터프리터에서 자료 구조를 다루는 스레드 연산은 두 바이트코드 명령어 사이에서 인터럽트 될 수 있다고 한다. 파이썬 인터프리터는 모든 쓰레드가 거의 동등한 처리 시간 동안 실행하게 하려고 공평성을 유지한다. 즉 파이썬은 공평성을 유지하려고 실행 중인 쓰레드를 잠시 중지하고 차례로 다른 쓰레드를 재개한다. 하지만 문제는 파이썬이 쓰레드를 정확히 언제 중지할지 모른다. (똑똑하게 코딩하는법 파이썬 코딩의 기술 참고)

 

다른 예제와 더 정확한 설명은 아래 블로그를 참고하였다.

 

Python의 Global Interpreter Lock(GIL)

파이썬은 느립니다. 다른 언어들에 비하면 정말 많이 느립니다. 동적 타입 시스템을 사용하며 인터프리터 언어라는 것만으로도 충분히 설명이 가능하지만 파이썬은 느리게 만드는 원인이 하나

xo.dev

 

왜 Python에는 GIL이 있는가

Python 사용자라면 한 번 쯤은 들어봤을 (안 들어봤다 해도 괜찮아요) 악명 높은 GIL (Global Interpreter Lock)에 대해 정리해본다. Global Interpreter Lock 그래서 GIL은 무엇인가? Python Wiki에서는 이렇게..

dgkim5360.tistory.com

다음 포스팅은 많은 함수를 동시에 실행하기 위한 코루틴에 대해 적으려고한다.

728x90

'Computer Science' 카테고리의 다른 글

Python - native coroutine  (0) 2021.04.07