동시성과 병렬성
| 시간 | 일 |
|---|
| T0 | A0 |
| T1 | B0 |
| T2 | C0 |
| T3 | D0 |
| T4 | A1 |
| ... | ... |
| T15 | D3 |
| 시간 | 코어0 | 코어1 | 코어2 | 코어3 |
|---|
| T0 | A0 | B0 | C0 | D0 |
| T1 | A1 | B1 | C1 | D1 |
| T2 | A2 | B2 | C2 | D2 |
| T3 | A3 | B3 | C3 | D3 |
프로세스(Process)와 쓰레드(Thread)
- 운영체제에서 어떤 실행 프로그램이 실행된다는 것은 CPU, 메모리(RAM), SSD와 같은 컴퓨터 자원을 사용
- 응용 프로그램은 운영체제 위에서 동작.
- 운영체제는 프로그램들이 실행될 전용 메모리 공간을 제공해주는데 이를 프로세스(Process) 라고 함
- 응용 프로그램의 코드는 프로세스내에서 실행됨.
- 어떤 코드가 프로세스 공간을 벗어날려 할 경우 운영체제에 의해 종료됨.
- 프로세스의 실행 단위로 쓰레드(Thread) 가 있음.
- 어떤 응용 프로그램은 한번에 여러 작업을 수행해야 할 경우가 있음.
- 이 경우 같은 프로세스에서 두 쓰레드가 컴퓨터 자원을 공유.
import threading
import time
class Worker(threading.Thread):
def __init__(self, name):
super().__init__()
self.name=name
def run(self):
print("sub thread start ", threading.currentThread().getName())
time.sleep(3)
print("sub thread end ", threading.currentThread().getName())
print("main thread start")
for i in range(5):
name="thread {}".format(i)
t=Worker(name)
t.start()
print("main thread end")
실행결과
main thread start
sub thread start thread 1
sub thread start thread 2
sub thread start thread 3
sub thread start thread 4
main thread end
/var/folders/_w/026hc9s93_g9d4gj2jbc0lw00000gn/T/ipykernel_55632/4204910620.py:9: DeprecationWarning: getName() is deprecated, get the name attribute instead
print("sub thread end ", threading.currentThread().getName())
sub thread end sub thread end thread 1
sub thread end thread 2
sub thread end thread 3
thread 4
데몬 쓰레드(Daemon Thread)
- 데몬 쓰레드는 메인 쓰레드가 종료될때 자신의 실행 상태와 상관없이 종료되는 서브 쓰레드를 의미.
- threading 모듈을 사용해서 메인 쓰레드가 서브 쓰레드를 생성할 경우 메인 쓰레드는 서브 쓰레드가 모두 종료될 때까지 기다렸다가 종료됨.
- 실제 프로그래밍을 하다보면 경우에 따라 메인 쓰레드가 종료되면 모두 서브쓰레드가 동작 여부에 상관없이 종료되어야 하는 경우가 많음
- 특히 토렌트와 같은 파일 다운로드 프로그램에서 서브 쓰레드를 통해 파일을 동시에 다운로드 받고 있는데 사용자가 메인 프로그램을 종료하면 파일의 다운로드 완료 여부와 상관없이 프로그램이 종료되어야 할 것이다.
- 이때 서브 쓰레드들은 데몬 쓰레드로 만들어져야함.
- 파이썬 threading모듈에서 데몬 쓰레드 생성은 daemon 속성을 True로 변경.
import threading
import time
class Worker(threading.Thread):
def __init__(self, name):
super().__init__()
self.name=name
def run(self):
print("sub thread start ", threading.currentThread().getName())
time.sleep(3)
print("sub thread end ", threading.currentThread().getName())
print("main thread start")
for i in range(5):
name="thread {}".format(i)
t=Worker(name)
t.daemon=True
t.start()
print("main thread end")
fork와 join
- fork: 메인쓰레드가 서브쓰레드를 생성하는 것
- join: 쓰레드가 끝날 때까지 기다리는것
import threading
import time
class Worker(threading.Thread):
def __init__(self, name):
super().__init__()
self.name=name
def run(self):
print("sub thread start ", threading.currentThread().getName())
time.sleep(5)
print("sub thread end ", threading.currentThread().getName())
print("main thread start")
t1=Worker("1")
t1.start()
t2=Worker("2")
t2.start()
t1.join()
t2.join()
print("main thread post job")
print("main thread end")
import threading
import time
class Worker(threading.Thread):
def __init__(self, name):
super().__init__()
self.name=name
def run(self):
print("sub thread start ", threading.currentThread().getName())
time.sleep(5)
print("sub thread end ", threading.currentThread().getName())
print("main thread start")
threads=[]
for i in range(3):
thread=Worker(i)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
print("main thread post job")
print("main thread end")
루틴(routine)과 서브루틴(subroutine)
- 루틴: 함수를 호출하는 쪽
- 서비루틴: 호출된 함수
- 루틴이 서브루틴을 호출한 경우 서브루틴이 리턴할때까지 루틴은 대기
- 서브루틴 종료후 원래의 루틴으로 돌아오며 이때 서브루틴이 리턴한 값을 루틴에서 사용.
def hap(a, b):
return a+b
ret=hap(3, 4)
print(ret)
코루틴(Corutine)
- 코루틴: 기존의 함수와 달리 함수를 호출하는 쪽인 루틴에 종속적이지 않으며 협동이 가능.
멀티프로세싱
- 파이썬 코드를 실행하면 인터프리터가 코드를 해석한 후 실행.
- 프로세스 관점에선 이를 메인 프로세스라 부름.
- multiprocess 모듈의 current_process 함수 호출시 실행중인 프로세스에 대한 정보를 담고있는 객체를 얻을수 있음.
- 해당 객체의 name과 pid 속성에 접근하면 프로세스의 이름과 PID(Process ID)를 얻을수 있음.
- PID란 운영체제가 각 프로세스에 부여한 고유 번호로 프로세스의 우선 순위를 조정하거나 종료하는 등 다양한 용도로 사용.
import multiprocessing as mp
if __name__=="__main__":
proc=mp.current_process()
print(proc.name)
print(proc.pid)
- 스포닝: 부모 프로세스가 운영체제에 요청하여 자식 프로세스를 새로 만들어내는 과정
- multiprocessing 모듈에서 프로세스 스포닝은 Process 클래스의 인스턴스를 생성후 start() 메소드를 호출
- Process 클래스의 인스턴스를 생성할 때 생성될 자식 프로세스의 이름과 위함하고자 하는 일(함수)을 전달.
import multiprocessing as mp
import time
def worker():
proc=mp.current_process()
print(proc.name)
print(proc.pid)
time.sleep(5)
print("SubProcess End")
if __name__=="__main__":
proc=mp.current_process()
print(proc.name)
print(proc.pid)
p=mp.Process(name="SubProcess", target=worker())
p.start()
print("MainProcess End")