프로세스와 쓰레드

장현빈·2024년 11월 28일

python

목록 보기
7/8

동시성과 병렬성

시간
T0A0
T1B0
T2C0
T3D0
T4A1
......
T15D3

시간코어0코어1코어2코어3
T0A0B0C0D0
T1A1B1C1D1
T2A2B2C2D2
T3A3B3C3D3

프로세스(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")
profile
인공지능 관련 분야에 관심있습니다.

0개의 댓글