process VS thread
multiprocessing과 multithreading의 차이는 process와 thread의 차이에서 기인한다. 먼저 process와 thread가 어떤 역할을 하는지부터 알아야한다.
위의 그림을 바탕으로 쉽고 빠르게 이해해보자.
먼저 CPU 하나에서 진행되는 작업을 process라고 하고, 하나의 process는 여러 개의 thread를 포함하고 있다.
이 때 하나의 process 내 thread 들은 메모리를 공유할 수 있다.
그리고 두 가지의 실행방법이 있는데,
첫 번째는 한 process 내의 여러 thread를 실행하는 것으로, concurrent execution이라고 한다. 이는 곧 multithreading이다.
두 번째는 여러 process를 동시에 실행하는 것으로, parallel execution이라고 한다. 이는 곧 multiprocessing이다.
참고로 두 가지 방법 모두 process나 thread를 2배, 3배로 늘린다고 해서 실행 속도가 2배, 3배가 되지는 않는다.
process의 경우 process 관리(초기화)에 비용이 들어가고 메모리를 공유하지 않기 때문에 해당 부분에서 시간이 소요된다.
thread의 경우 GIL에 의한 오버헤드의 문제가 있을 수 있다.
장단점
multiprocessing
- 장점
- 병렬 처리로 빠른 실행
- CPU 최대 활용 → 임대 컴퓨터 시스템이나 클라우드 기반 서비스 사용 시 비용 절감
- 단점
- 코어 수 만큼만 병렬 처리 가능
- 스레드에 비해 무겁고 더 많은 리소스 필요
- 프로세스 간 통신 느림
multithreading
- 장점
- 프로세스에 비해 가볍고 적은 리소스 필요
- 메모리 공간을 공유하기 때문에 스레드 간 통신 빠름
- 프로세스 최대 활용
- 단점
- Python에서는 GIL(Global Interpreter Lock)으로 인해 CPU 연산량이 많은 프로그램에 대해 성능향상보다 병목을 만들 수 있음
GIL이란?
- Global Interpreter Lock의 약자
- 하나의 스레드만 파이썬 인터프리터를 제어하도록 Lock 하는 것
- 메모리 안전성을 보장
- 멀티 스레드가 싱글 스레드처럼 동작하는 성능병목 현상
- 기본 Python 인터프리터 cPython의 일부
multiprocessing | multithreading |
프로세스 사용 | 스레드 사용 |
무겁고 큰 메모리 공간 | 가볍고 메모리 사용량이 적음 |
고유한 독립 메모리 공간 | 상위 프로세스와 공유 메모리 공간 |
메모리 주소와 공간이 다르기 때문에 어려움 | 공유 메모리 공간으로 인해 쉬움 |
느린 새 프로세스 생성 | 빠른 새 스레드 생성 |
진정한 병렬 처리 구현 여러 CPU와 프로세서를 활용 | GIL로 인해 성능병목현상 발생 가능 |
multiprocessing 모듈 | threading 모듈 |
실행하는 데 더 많은 시스템 리소스가 필요 | 실행하는 데 필요한 시스템 리소스가 더 적음 |
어떤 경우에 사용할까?
- multiprocessing : CPU intensive tasks, 즉 CPU를 많이 사용하는 계산량이 많은 여러 작업을 실행하고 싶은 경우
- multithreading : I/O intensive tasks, 즉 CPU를 많이 사용하지는 않지만 읽고 쓰는 여러 작업을 실행하고 싶은 경우
모듈 사용 예시
multiprocessing
말 그대로 multiprocessing을 실행할 수 있는 모듈이다. 이 모듈에 대해서는 이전 포스팅에서 설명했기 때문에 참고하자.
multiprocessing 포스팅 https://im-so-so.tistory.com/114
threading
공식 문서 https://docs.python.org/3/library/threading.html
import threading
import time
def add(num1, num2):
time.sleep(3)
print(num1 + num2, time.ctime())
def main():
thread1 = threading.Thread(target=add, args=(1, 2))
thread2 = threading.Thread(target=add, args=(2, 3))
thread3 = threading.Thread(target=add, args=(3, 4))
thread1.start()
thread2.start()
thread3.start()
main_thread = threading.current_thread()
for thread in threading.enumerate():
if thread is main_thread:
continue
thread.join()
print(thread.name, thread.is_alive())
print("done!")
for thread in threading.enumerate():
print(thread.name, thread.is_alive())
if __name__ == "__main__":
main()
output >>> 같은 시간에 출력된 것을 바탕으로 병렬 처리가 잘 이루어 졌음을 알 수 있다.
7 Fri Aug 18 16:17:24 2023
5 Fri Aug 18 16:17:24 2023
3 Fri Aug 18 16:17:24 2023
Thread-1 (add) False
Thread-2 (add) False
Thread-3 (add) False
done!
MainThread True
- 현재 가지고 있는 모든 thread 를 threading.enumerate()로 가져온다.
- thread 작업을 join() 메서드로 종료를 기다린다. 이 때, main thread는 넘어간다.
- 각 thread.name을 출력하고, 각 thread가 잘 종료되었는지(아직 살아있는지) is_alive() 로 확인한다.
- join이 완전히 끝났다면 print(“done!”) 후 어떤 thread가 남아있는지(살아있는지) 확인한다.
concurrent.features
공식 문서 https://docs.python.org/3/library/concurrent.futures.html
multiprocessing - ProcessPoolExecutor
import time
from concurrent.futures import ProcessPoolExecutor
def add(num1, num2):
time.sleep(3)
print(num1 + num2, time.ctime())
def main():
with ProcessPoolExecutor(max_workers=3) as executor:
executor.submit(add, 1, 2)
executor.submit(add, 2, 3)
executor.submit(add, 3, 4)
print("done!")
if __name__ == "__main__":
main()
multithreading - ThreadPoolExecutor
import time
from concurrent.futures import ThreadPoolExecutor
def add(num1, num2):
time.sleep(3)
print(num1 + num2, time.ctime())
def main():
with ThreadPoolExecutor(max_workers=3) as executor:
executor.submit(add, 1, 2)
executor.submit(add, 2, 3)
executor.submit(add, 3, 4)
print("done!")
if __name__ == "__main__":
main()
output >>> 같은 시간에 출력된 것을 바탕으로 병렬 처리가 잘 이루어 졌음을 알 수 있다.
3 Fri Aug 18 16:23:21 2023
5 Fri Aug 18 16:23:21 2023
7 Fri Aug 18 16:23:21 2023
done!
'Python' 카테고리의 다른 글
[python error] 크롤링 중 발생한 에러 (0) | 2023.08.29 |
---|---|
[python] asyncio - async, await 사용하기 (0) | 2023.08.24 |
[python] FastAPI vs Flask 비교 (0) | 2023.08.23 |
[python] Flask 기초 사용법 (0) | 2023.08.22 |
[python] pydantic 알아보기 (0) | 2023.08.21 |