CS
쓰레드와 프로세스 공부하기
foxlee
2022. 1. 11. 23:06
- 이 글은 크롤링을 이용한 데이터 수집 시, 구글 API에 이미지 업로드시 적용하기 위해 공부하게 되었다.
프로세스와 쓰레드 + 멀티 프로세스, 멀티쓰레드 비교
- 프로세스
- 운영체제로부터 할당 받는 자원 단위(실행 중인 프로그램)
- CPU동작 시간, 주소공간, Code, Data, Stack, Heap - 독립적
- 최소 1개의 메인쓰레드 보유
- 파이프, 파일, 소켓등을 사용해서 프로세스간 통신 Context Switching - Cost 높음
- 많은 메모리 필요, 데드프로세스 생성 가능성 높음, 오버헤드 큼, 생성 소멸 느림
- 쓰레드
- 프로세스 내에 실행 흐름 단위로서 프로세스의 자원을 사용
- Stack만 별도 할당(함수의 시작점, 끝나는 부분등) 나머지는 공유(Code, Data, Heap)
- 메모리 공유(변수 공유) -> 한 쓰레드의 결과가 다른 쓰레드에 영향 끼침
- 동기화 문제 및 디버깅 어려움
- 적은 메모리, 오버헤드 작고, 생성 소멸 빠름
- 멀티 쓰레드
- 한 개의 단일 어플리케이션(응용프로그램)에서 여러 쓰레드로 구성하여 작업 처리
- 시스템 자원 소모 감소, 처리량 증가, 통신 부담 감소, 디버깅 어려움
- 단일 프로세스에는 효과 미약, 자원 공유 문제(교착상태), 프로세스 영향
- i/o 작업에 적합(네트워크, 입출력 등)
- 파이썬 - 쓰레드는 가볍지만 GIL로 인해 계산 처리를 하는 작업은 한번에 하나의 쓰레드에서만 작동하여 cpu 작업이 적고 I/O 작업이 많은 병렬 처리 프로그램에서 효과를 볼 수 있음
- 멀티 프로세스
- 한 개의 단일 어플리케이션(응용프로그램) -> 여러 프로세스로 구성 후 작업 처리
- 한 개의 프로세스 문제 발생은 확산 없음(프로세스 Kill)
- 캐시 체인지, Cost 비용 매우 높음(오버헤드), 복잡한 통신 방식 사용
- cpu 계산이 많은 작업에 적합
- 프로세스는 각자가 고유한 메모리 영역을 가지기 때문에 더 많은 메모리를 필요로 하지만, 각각 프로세스에서 병렬로 cpu 작업을 할 수 있고 이를 이용해 여러 머신에서 동작하는 분산 처리 프로그래밍도 구현할 수 있다.
- GIL(Global Interpreter Lock)
- 언어에서 자원을 보호하기 위해 락(Lock) 정책을 사용
- CPython -> Python(bytecode) 실행 시 여러 thread 사용 할 경우 단일 쓰레드만이 Python object에 접근 하게 제한하는 mutex
- Thread-safe 을 위함
- 파이썬에서는 하나의 프로세스 안에 모든 자원의 락(Lock)을 글로벌(Global)하게 관리함으로써 한번에 하나의 쓰레드만 자원을 컨트롤하여 동작하도록 함
- 두 개의 쓰레드를 동시에 실행시키지만, 결국 GIL 때문에 한번에 하나의 쓰레드만 계산을 실행하여 실행 시간이 비슷
- GIL이 적용되는 것은 cpu 동작에서이고 쓰레드가 cpu 동작을 마치고 I/O 작업을 실행하는 동안에는 다른 쓰레드가 cpu 동작을 동시에 실행할 수 있다. 따라서 cpu 동작이 많지 않고 I/O동작이 더 많은 프로그램에서는 멀티 쓰레드만으로 성능적으로 큰 효과를 얻을 수 있다.
쓰레드
- 데몬쓰레드
- 백그라운드에서 실행
- 메인쓰레드 종료시 즉시 종료(예 __name__ == __main__ 아래 부분에 코드 - 메인 쓰레드
- 주로 백그라운드 무한 대기 시 이벤트 발생시 실행하는 부분 담당
- 일반 쓰레드는 작업 종료시 까지 실행
- 그룹쓰레드(Python 3.2 이상 표준 라이브러리 사용)
- concurrent.futures
- with사용으로 생성, 소멸 라이프사이클 관리 용이
- 디버깅 어려움
- 대기중인 작업은 Queue 에 넣고 완료 상태 조사 후 결과 또는 예외 처리하여 단일화(캡슐화)
관련 키워드
- Concurrent : 논리적인 용어로 동시에 실행되는 것처럼 보이는것을 말합니다. 싱글코어(또는, 멀티코어)에서 멀티 쓰레드를 동작시키기 위한 방식으로 멀티 태스킹을 위해 여러 스레드를 번갈아 가면서 실행되는 방식(한 개의 작업 공유 처리)
- Parallelism : 완전히 동일한 타이밍(시점)에 복수의 작업 실행, 다양한 파트(부분)으로 나눠서 실행, 실행 후 합침(멀티프로세싱에서 CPU가 1Core 인 경우 만족하지 않음) - 주로 별개의 작업 처리
- Semaphore : 프로세스간 공유된 자원에 접근 시 상호 배제를 위해 사용 - 경쟁상태 예방
- 뮤텍스(Mutex) : 공유된 자원의 데이터를 여러 쓰레드가 접근하는 것을 막는 것 - 경쟁상태 예방
- Lock : 상호 배제를 위한 잠금(Lock)처리 - 데이터 경쟁
- 데드락(Deadlock) : 프로세스가 자원을 획득하지 못해 다음 처리를 못하는 무한 대기 상황 -교착상태
- Thread synchronization(쓰레드 동기화)를 통해서 안정적으로 동작하게 처리한다.(동기화메소드, 동기화 블록)
- Semaphore와 Mutex의 차이점
- 세마포어와 뮤텍스 개체는 모두 병렬 프로그래밍 환경에서 상호 배제를 위해 사용
- 뮤텍스 개체는 단일 쓰레드가 리소스 또는 중요 섹션을 소비 허용
- 세마포는 리소스에 대한 제한된 수의 동시 액세스를 허용
멀티 쓰레드 생산자-소비자 패턴
- 생산자 - 작업을 생산해내는 주체로서 작업을 만들어 큐에 넣음(최적 - 디스크 I/O, 네트워크 작업 등)
- 소비자 - 작업을 처리하는 주체로서 큐에 쌓여 있는 작업을 가져다 처리(최적 - CPU 작업)
- 큐의 작업 크기를 제한하여 생산자는 큐에 작업을 추가하면서 큐에 공간이 없으면 대기하고, 소비자는 큐에서 작업을 가져가고, 작업이 없으면 작업이 생길때까지 대기
구글 드라이브 API 이미지 업로드 멀티 쓰레드 이슈
- 어떤 이슈로 복수개의 이미지들이 업로드 되지 않는 경우 업로드 하기 위해 멀티쓰레딩으로 구현하려고 했으나,
- 멀티쓰레딩의 경우 thread safety 이슈로 인해 정상 작동하지 않음
- 각 요청시마다 새로운 AuthrizedHttp http 인스턴스를 보내줘야함
https://github.com/googleapis/google-api-python-client/blob/main/docs/thread_safety.md
GitHub - googleapis/google-api-python-client: 🐍 The official Python client library for Google's discovery based APIs.
🐍 The official Python client library for Google's discovery based APIs. - GitHub - googleapis/google-api-python-client: 🐍 The official Python client library for Google's discovery based APIs.
github.com