CPU 확장 이유?
- CPU 속도는 무한히 빨라질 수 없으므로, 애플리케이션에 동시성 + 병렬성 도입
CPU 확장 방법
1. 스레드
<장점>
- 여러 함수를 동시에 실행하기에 좋다
- 싱글 CPU : 스레드 차례로 실행
- 멀티 CPU : 여러 CPU에서 스레드 실행
<단점>
- GIL의 제약으로 완벽한 확장 솔루션이 아님
import threading
def print(line):
print(line)
# 스레드 실행 후 완료 대기
t = threading.Thread(target=print, args("multithread Hi",))
t.start()
print("threading start")
# 스레드 완료될 때까지 메인 스레드 대기
t.join()
- 스레드를 데몬으로 돌리면 백그라운드 스레드로 간주됨.
- 메인 스레드 종료 후 같이 종료
import threading
def print(args):
print(args)
t = threading.Thread(target=print, args("hello",))
t.daemon = True
t.start()
# 데몬으로 실행했기 때문에, join 함수 필요 없음
코어 개수만큼 병렬로 실행해보기
import random
import threading
results = []
def compute():
results.append(sum([random.randint(1,100) for i in range(100000)]))
workers = [threading.Thread(target=compute) for x in range(8)]
for worker in workers:
worker.start()
for worker in workers:
worker.join()
print("Results: %s"% results)
위의 코드를 실행하면 알겠지만,
코어가 4개라면 최대 400% CPU를 사용할 수 있어야한다.
하지만, 시스템의 CPU에 접근하기 위해서는 CPython의 GIL이 지키고 있는 구간을 통과해야하기 때문에 병목 현상이 발생한다.
- GIL은 멀티 스레드를 실행할 때, CPython 성능 제한
- 스레드는 병렬 컴퓨팅, 네트워크, 파일처럼 느린 입출력을 처리할 때 유용
- 위의 작업은 메인 스레드를 차단하지 않고 병렬 실행 가능
결론 : 여러 CPU를 사용해서 처리량을 늘리기 위해서는 프로세스 사용하는 것이 좋다.
2. 프로세스
일정 시간동안 작업 일부를 병렬화할 수 있다면 threading 모듈보다
multiprocessing 모듈과 작업 분기를 통해 CPU 여러 개에 부하를 분산하는 것이 더 좋다.
import random
import multiprocessing
def compute(results):
results.append(sum([random.randint(1,100) for i in range(10000)]))
with multiprocessing.Manager() as manager:
results = manager.list()
workers = [multiprocessing.Process(target=compute, args=(results,)) for x in range(8)]
for worker in workers:
worker.start()
for worker in workers:
worker.join()
print("Results: %s" % results)
- 다른 프로세스 간에 공유 가능한 데이터가 없으므로 작성하기가 까다로움.
- 각 프로세스는 새로운 독립적 파이썬이므로, 데이터는 복사되며 각 프로세스는 고유한 전역상태를 가짐
- multiprocessing.Manager 클래스는 동시 접근에 안전한 공유 데이터 구조를 만든다.
멀티 프로세싱은 pool 매커니즘을 제공한다.
import multiprocessing
import random
def compute(n):
return sum([random.randint(1,100) for i in range(10000)])
pool = multiprocessing.Pool(processes=8)
print("Results: %s" % pool.map(compute, ranger(8)))
multiprocessing.Pool을 사용하면 프로세스 자동 관리
'Developer > Python' 카테고리의 다른 글
[Python] 파이썬 이벤트 루프 (0) | 2020.12.29 |
---|---|
[Python] 파이썬에서 IP 버전 확인하기 (0) | 2020.07.30 |
[Python] 파이썬에서 텔넷(telnet) 사용하기 (1) | 2020.07.29 |
[Python] dict 딕셔너리 키-값 출력 (0) | 2020.07.24 |
[Python] 파이썬 CPU 확장 방법 2 (퓨처스) (0) | 2020.05.11 |