빅데이터를 다루기 위해서는 컴퓨팅 자원을 최적화하는 방법인 병렬 컴퓨팅, 분산 컴퓨팅 등 개념을 알아야한다.
컴퓨터 아키텍처를 설계하는 사람들만의 고민들이 아니며, 현실세계에서 새로 라면집을 개업한 김사장님도 비슷한 고민을 한다.
주방장 1명이 라면 1개를 끓이는 데 시간은 아래와 같이 총 10분이 소요된다.
주방장이 쉬지않고 일해도 1시간에 라면을 최대 6개밖에 끓여내지 못한다.
이때 2가지 아이디어를 생각해 내는데, 바로 동시성과 병렬성 이다.
아래에 이어지는 비유와 함께 아래 링크의 글을 함께 참고하면 동시성, 병렬성을 이해하는 데 도움이 됩니다.
재료를 준비하거나 서빙을 하는 시간은 몰라도,
물을 끓이거나 라면을 끓이는데 소요되는 7분 동안에는 얼마든지 다른 라면을 끓이기 위한 작업은 가능해 보인다.
하나의 processor가 여러 가지 task를 동시에 수행하는 개념을 동시성이라 한다.
주방장을 한 명 더 고용한다면 라면 나오는 속도는 지금의 2배가 될것이며,
유사한 task를 여러 processor가 동시에 수행하는 것을 병렬성이라고 한다.
병렬성의 효율을 극대화하는 것은 동시성이 요구될때 이며, 여러 개의 프로세스가 1개의 task를 여러 개의 subtask로 쪼개어 동시에 병렬적으로 수행할 수 있다.
어떤 일을 바로 하지 못하고 대기해야 하는 일을 일컬을 때 컴퓨터에서는 "바운드(bound) 되었다"라는 표현을 쓰며, 이런식의 바운드가 발생하면 계속 기다려야 할지 아니면 종료되는 사이에 다른 걸 실행하는 것이 좋을지 고민이 생긴다.
출처 : https://poiemaweb.com/js-async
What do the terms “CPU bound” and “I/O bound” mean?
우리는 PPT 문서 작업을 하면서, 노래를 듣기도 하고, 웹 브라우저를 이용해 검색을 한다.
오늘날의 컴퓨터에서는 이런식의 여러 개 프로그램을 동시에 실행시키는 멀티태스킹이 기본 사양이다.
"프로그램을 구동하여 프로그램 자체와 프로그램의 상태가 메모리상에서 실행되는 작업 단위"
파이썬에서는 os
라는 모듈에서 프로세스 관련 정보를 확인해볼 수 있다.
어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위
출처 : https://en.wikipedia.org/wiki/Thread_(computing)
코드에서 시스템의 어느 부분이 느린지 혹은 어디서 RAM을 많이 사용하고 있는지를 확인하고 싶을 때 사용하는 기법
파이썬에서는 다음 명령어로 확인할 수 있다.
%timeit
----------------
import time
time.time()
----------------
import timeit
timeit.Timer()
- 프로파일링은 애플리케이션에서 가장 자원이 집중되는 지점을 정밀하게 찾아내는 기법
- 프로파일러는 애플리케이션을 실행시키고 각각의 함수 실행에 드는 시간을 찾아내는 프로그램
- 코드의 병목(bottleneck)을 찾아내고 성능을 측정해 주는 도구
profile
,cProfile, line_profiler 패키지들을 사용하면 좀 더 상세한 프로파일링이 가능하다.
컴퓨터 자원을 Up(업그레이드, 최적화)시킬 수도 있고, 자원을 Out(확장)시킬 수도 있다.
출처 : https://akdl911215.tistory.com/291
파이썬에서 멀티스레드의 구현은 threading
모듈을 이용한다.
threading — Thread-based parallelism
threading
모듈의 Thread
클래스를 상속받아서 구현할 수도 있지만,
그대로 인스턴스화하여 스레드를 생성할 수도 있다.
인스턴스화 하려면 Thread 클래스에 인자로 target과 args 값을 넣어준다.
t = Thread(target=함수이름, args=())
스레드 함수가 루프를 돌 때는 꼭 멈춰야 할지를 체크하는 flag를 체크하도록 설계해야 한다.
파이썬에서 멀티프로세스의 구현은 multiprocessing
모듈을 사용하면 된다.
multiprocessing - Process-based parallelism - Python 3.7.9 documentation
프로세스 또한 스레드와 유사한 방법으로 생성한다.
Process
인스턴스를 만든 뒤, target
과 args
파라미터에 각각 함수 이름과 함수 인자를 전달하면 된다.
import multiprocessing as mp
def delivery():
print('delivering...')
p = mp.Process(target=delivery, args=())
p.start()
Process
클래스는 start()
, join()
, terminate()
같은 프로세스 동작 관련한 메소드들이 있다..
p = mp.Process(target=delivery, args=())
p.start() # 프로세스 시작
p.join() # 실제 종료까지 기다림 (필요시에만 사용)
p.terminate() # 프로세스 종료
"풀"이란 영어로 Pool이다. 스레드나 프로세스들로 가득 사용한다 생각하면 되며, 스레드 풀을 만들면 각각의 태스크들에 대해 자동으로 스레드들을 할당하고 종료한다.
[풀을 만드는 방법은 2가지]
ThreadPoolExecutor
, ProcessPoolExecutor
클래스를 이용하는 방법[기능은 크게 4가지]
ThreadPoolExecutor
객체ProcessPoolExecutor
객체Future
객체Executor
객체를 이용하면
위와 같은 작업을 할 때, with 컨텍스트 관리자와 같은 방법으로 가독성 높은 코드를 구현할 수 있다.
with ThreadPoolExecutor() as executor:
future = executor.submit(함수이름, 인자)
multiprocessing.Pool.map
을 통해 여러 개의 프로세스에 특정 함수를 매핑해서 병렬처리하도록 구현하는 방법이 가장 많이 사용된다.