[Python] Multi thread & Multi process

도갱도갱·2022년 2월 11일
0

Python

목록 보기
27/34

Multi thread & Multi process

  • 파이썬은 인터프리터 언어로서 기본적으로 싱글 thread에서 순차적으로 동작한다.

Multi thread

  • thread 기반 병렬처리 방법으로 threading 모듈의 Thread 함수로 thread 객체를 받아 사용한다.

  • threading 모듈을 사용해 멀티 thread를 구현할 수 있다. thread 모듈은 deprecated 되었다

  • thread는 가볍지만 한번에 하나의 thread만 CPU 작업이 가능하다.

  • thread는 같은 process에 속한 다른 thread들과 코드 영역, 데이터 영역, 운영체제의 다른 자원(File, Signal)을 공유한다.

thread 생성

from threading import Thread
th =Thread(name=, target=, args=(), kwargs={}, daemon=)
  • name : thread 이름. 로깅 등의 용도로 사용되며 설정하지 않아도 무방하다

  • target : thread에서 실행할 함수

  • args : target 함수에 넘겨질 인자. tuple 형식으로 넘겨줘야 한다.

  • kwargs : target 함수에 넘겨질 키워드 인자. dict 형식으로 넘겨줘야 한다.

  • daemon : 데몬 실행 여부. 데몬으로 실행되는 thread는 프로세스가 종료될 때 즉각 중단된다.


thread 매소드

  • start()
    thread 시작
  • join()
    해당 thread에서 실행되는 함수가 종료될 때까지 대기
    timeout 인자를 사용하면 특정 시간까지만 대기하도록 한다. 시간을 초과하면 예외 발생없이 None을 리턴한다.
  • is_alive()
    is_alive() 함수를 통해 thread가 실행 중인지 확인할 수 있다.

+ join() 예제
join() 함수의 기능이 잘 이해되지 않아서 아주 간단한 코드를 짜보았다.
th7이 실행된 직후 'we'를 출력하는 첫번째 print도 실행되었다.
두번째 print는 join 함수로 인해 th8이 종료된 이후에 실행된다.

def wrt(wrtid, num):
   for i in range(0, num):
       print(0, num)
        
th7 = Thread(target=wrt, args=(1, 5))
th8 = Thread(target=wrt, args=(1, 5))
th7.start()
print("we")
th8.start()
th7.join()
th8.join()
print("we")

thread 속성

  • ident
    thread 식별자. 종료된 thread 이후에 새로 만들어진 다른 thread에 재활용 될 수 있다.

  • natived_id
    thread 고유 식별자.

  • daemon
    daemon thread 여부. default는 Fasle.
    daemon thread란 백그라운드에서 실행되는 thread로 main thread가 종료되면 즉시 종료된다.


Multi thread의 GIL

  • GIL(Global Interpreter Lock)은 자원을 보호하기 위한 Lock 정책이다.
  • Multi thread는 하나의 프로세스 안에 모든 자원의 Lock을 글로벌하게 관리함으로써 한번에 하나의 thread만 자원을 컨트롤하여 동작하도록 한다.
  • 아래는 thread 1개와 thread 2개의 실행시간을 비교하는 코드이다.
from threading import Thread
import time 
  
rList = list()
def wrtL(wrtid, num):
    for i in range(0, num):
        rList.append(i)
        
# thread 1개
th3 = Thread(target=wrtL, args=(1,20000000))
start = time.time()
th3.start()
th3.join()
end = time.time()
print(end - start) 
  
# thread 2개
th1 = Thread(target=wrtL, args=(1,10000000))
th2 = Thread(target=wrtL, args=(2,10000000))
start = time.time()
th1.start()
th2.start()
th1.join()
th2.join()
end = time.time()
print(end - start)
  • thread 1개

  • thread 2개

  • 출력결과 thread 2개를 사용한 실행시간이 thread 1개를 사용한 경우와 큰 차이가 없다. multi thread를 사용해도 GIL 정책으로 rList라는 자원을 공유하는 두 thread는 순차적으로 실행되기 때문이다.
  • GIL이 적용되는 것은 CPU 동작이며 이것을 마치고 I/O 작업을 실행하는 동안 다른 thread가 CPU 동작을 동시에 실행할 수 있다. 따라서 CPU 동작이 많지 않고 I/O 작업이 더 많은 프로그램에서는 Multi thread가 효과적이다.

Multi process

Multi process 실행

  • Multi process는 thread 대신 process를 만들어 병렬처리를 실행한다.

  • multiprocessing 모듈의 Process 함수를 사용한다.

  • process는 각자 고유한 메모리 영역을 가지기 때문에 thread에 비해 메모리 사용량이 늘어나는 단점이 있지만 CPU 작업을 병렬로 실행할 수 있는 장점이 있다. 여러 머신에서 동작하는 분산 처리 프로그래밍 구현도 가능하다.

  • 프로세스간 데이터 교환을 위해 multiprocessing.Queue 객체를 사용해야 한다.


multi thread와 비교

  • 아래는 위의 multi thread 예제를 multi process로 실행하는 코드이다. multi thread 보다 시간이 더 단축된 것을 볼 수 있다.
from multiprocessing import Process, Queue
import time 

rQueue = Queue()
def wrtQ(wrtid, num):
    for i in range(0, num):
        rQueue.put(i)

# process 1개
start = time.time()
th6 = Process(target=wrtQ, args=(1,20000000))
th6.start()
th6.join()
end = time.time()
print(end - start)

# process 2개
th4 = Process(target=wrtQ, args=(1,10000000))
th5 = Process(target=wrtQ, args=(2,10000000))
start = time.time()
th4.start()
th5.start()
th4.join()
th5.join()
end = time.time()
print(end - start)
  • process 1개

  • process 2개



Reference

0개의 댓글