컴퓨터에 있는 모든 코어를 활용해 프로그램의 성능을 높이기 위해 멀티스레딩을 활용한다.
각 스레드에게 작업량을 미리 정해준다. 각 스레드에게 할당한 작업의 걸리는 시간이 비슷하다고 예측할 수 있을 때 사용한다. 각 스레드에게 작업을 분배하는데 걸리는 오버헤드가 적고 구현이 쉽다는 장점이 있지만, 작업을 적절히 분배하지 못하면 놀고 있는 스레드가 생길 수 있다.
파이썬의 리스트의 append()
함수는 Thread-safe 하기 때문에 따로 동시성 제어를 할 필요가 없다.
works = [x for x in range(1000)]
results = []
for work in works:
result = work * 1000
results.append(result)
print("Finished")
works
리스트에 존재하는 0부터 999까지의 원소에 1000을 곱한 결과를 results
리스트에 순서대로 저장한다.
import threading
def calculate(partial_works):
for work in partial_works:
result = work * 1000
results.append(work)
works = [x for x in range(1000)]
results = []
# 스레드 개수와 스레드 리스트
thread_count = 10
threads = []
# 새로운 스레드 생성/실행 후 스레드 리스트에 추가
for i in range(thread_count):
thread = threading.Thread(target=calculate, args=(works[i * 100 : (i + 1) * 100],),)
thread.start()
threads.append(thread)
# 메인 스레드는 각 스레드의 작업이 모두 끝날 때까지 대기
for thread in threads:
thread.join()
print("Finished")
파이썬에서 각 스레드는 target
으로 주어진 함수를 실행한다. 그리고 해당 함수의 매개변수는 args
를 통해 튜플 형태로 넘겨줄 수 있다. 튜플 특성 상 함수 매개변수가 하나일 땐 마지막에 ,
를 넣어줘야 한다. 그리고 메인 스레드는 각 스레드의 작업이 모두 끝난 후 Finished
를 출력한다. 주의할 점은 스레드의 실행 순서에 따라 results
리스트의 원소 순서가 달라질 수 있다는 것이다.
threading.Thread()
: 스레드를 새로 생성한다.
Thread.start()
: 해당 스레드가 target
으로 넘겨받은 함수를 병렬로 실행한다.
Thread.join()
: 해당 스레드(새로 생성된 스레드)의 실행이 끝날 때까지 join()
함수를 호출한 스레드(메인 스레드)는 대기한다.
요약하면,
각 스레드에게 작업을 그때 그떄 할당해주는 방식이다. 각 스레드에게 할당한 작업에 걸리는 시간을 예측할 수 없을 때 사용한다.