프로세스,스레드,멀티프로세싱, 멀티 스레딩
프로세스
프로세스는 기본적으로 메모리에 적재된다.(페이징을 통해 보조저장장치에 일부 저장되어있는 경우도 있다.) 사용자가 볼수 있는 공간에서 실행되느냐 아니냐에 따라 Foreground Process, Background process로 나뉜다. 백그라운드 프로세스중 대다수는 사용자와 직접 상호작용을하지 않고 정해진 일만 수행한다.(데몬/서비스) 포그라운드 프로세스가 백그라운드 프로세스로 전환될 때는 보통 사용자와 직접 상호작용을 할 수 있는 상태이다.
커널 영역에서의 관리
프로세스 제어블록(PCB)
프로세스 실행에는 CPU의 사용이 필요하지만 CPU는 한정된 리소스이다. 따라서 빠르게 번갈아 가며 한정된 시간동안만 사용해야하기 때문에 각 프로세스마다 고유한, 프로세스의 관련 정보를 저장하는 자료구조 PCB를 이용한다. 프로세스가 생성될 때 커널 영역에서 생성되고 종료될 때 폐기한다.
PID(고유번호), register value(pc포함), process state(실행중,중지, 일시중단...), 스케줄링정보, 메모리정보, 사용한파일과 입출력장치정보등이 기록된다.
같은 파일 다른 프로세스
메모리에 적재 된 것이 기준이므로, 같은 파일을 실행시키더라도 다른 메모리 영역을 가지고 다른 PCB를 가진다면 서로 다른 프로세스이다.
사용자 영역에서의 관리: 스택/힙/데이터/코드
메모리에 정해진 영역안에서 스택/힙/데이터/코드 영역을 차지한다.
- 코드: 명령어 저장. 쓰기 금기
- 데이터: 전역변수(실행부터 종료까지가 스코프) 저장
- 힙: 사용자가 직접 관리할 수 있는 공간
( 스택: 지역변수,매개변수들. 일시적 저장. 동적으로 크기 변함.
멀티프로세스와 멀티 스레드
모든 프로세스는 남남이다. 프로세스간 통신등으로 자원 주고받기는 가능하지만 이론적으로 모든 프로세스는 코드/데이터 등의 리소스를 따로 사용한다. (예외: copy on write)
'스레드'는 프로세스의 실행흐름을 의미한다. 멀티스레드는 하나의 프로세스내에서 둘 이상의 스레드가 동시에 수행되는 것이다. 프로세스의 자원(코드, 데이터, 파일)을 공유하여 좀더 경량이지만 스레드에 문제가 생기면 다른 스레드에도 문제가 발생할 수 있다.
각기 다른 스레드 아이디, 프로그램카운터 값을 포함한 레지스터값, 스택을 가진다.
파이선으로 프로세스 다루기
from multiprocessing import Process
import os
def func1():
print('=== I do task AA ===')
print('my pid', os.getpid())
print('my parents pid', os.getppid())
for i in range(1000):
print("A", i)
if __name__ == '__main__':
print('python root pid is', os.getpid()) # 12310
# different processes do a same task
changsu1 = Process(target=func1).start() #my pid 12330, my parents pid 12310
changsu2 = Process(target=func1).start() #my pid 12345, my parents pid 12310
multiprocessing 모듈을 사용해 멀티프로세싱을 다룰 수 있다.서로 같은 작업을 수행하거나 다른 작업을 수행하는 다른 프로세스들을 만들 수 있다. 다음과 같이 하면 동시에 수행되겠다고 서로 번갈아 가며 실행되는 모습을 볼 수 있다.
from multiprocessing import Process
import os
def func1():
for i in range(1000):
print('my pid', os.getpid())
if __name__ == '__main__':
print('python root pid is', os.getpid()) # 12310
# different processes do a same task
changsu1 = Process(target=func1).start() #my pid 2251
changsu2 = Process(target=func1).start() #my pid 2252
changsu3 = Process(target=func1).start() #my pid 2253

파이선으로 멀티 스레드 다루기
import threading
import os
def foo():
print('=== Me foo. Me do task A. ===')
print(f'thread id: {threading.get_native_id()}')
print(f'pid is: {os.getpid()}')
if __name__ == '__main__':
print(f'Im process. My pid is {os.getpid()}') # 20221
# threads do a same task
thread1 = threading.Thread(target=foo).start() # pid:20221, native_id=12390
thread2 = threading.Thread(target=foo).start() # pid:20221, native_id=12391
같은 프로세스안에서 서로 다른 두개의 스레드를 만들기 위해 threading 모듈을 import해올 수 있다. 각 스레드들은 서로 같은 작업을 수행할 수도 있고 다른 작업을 수행할 수도 있다.
import threading
from multi_process import Process
import os
def foo():
print('=== Me foo. Me do task A. ===')
print(f'thread id: {threading.get_native_id()}')
print(f'pid is: {os.getpid()}')
def bar():
print('=== Me bar. Me do task B. ===')
print(f'thread id: {threading.get_native_id()}')
print(f'pid is: {os.getpid()}')
def baz():
print('=== Me baz. Me do task C. ===')
print(f'thread id: {threading.get_native_id()}')
print(f'pid is: {os.getpid()}')
if __name__ == '__main__':
print(f'Im process. My pid is {os.getpid()}')
thread1 = threading.Thread(target=foo).start()
thread2 = threading.Thread(target=bar).start()
thread3 = threading.Thread(target=baz).start()
이런 경우 만약 foo,bar,baz가 전역변수를 사용하고 그 변수에 문제가 발생할 시 셋 모두 정지될 수 있다.