파이썬 멀티스레딩

곽태욱·2020년 7월 7일
0

목적

컴퓨터에 있는 모든 코어를 활용해 프로그램의 성능을 높이기 위해 멀티스레딩을 활용한다.

작업 할당

정적 할당

각 스레드에게 작업량을 미리 정해준다. 각 스레드에게 할당한 작업의 걸리는 시간이 비슷하다고 예측할 수 있을 때 사용한다. 각 스레드에게 작업을 분배하는데 걸리는 오버헤드가 적고 구현이 쉽다는 장점이 있지만, 작업을 적절히 분배하지 못하면 놀고 있는 스레드가 생길 수 있다.

파이썬의 리스트의 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() 함수를 호출한 스레드(메인 스레드)는 대기한다.

요약

요약하면,

  1. 병렬 처리할 부분을 함수로 만든다.
  2. 슬라이싱 등을 통해 작업을 분할한다.
  3. 각 스레드에게 함수와 분할된 작업을 건내준다.
  4. 각 스레드가 처리한 결과를 모은다.

동적 할당

각 스레드에게 작업을 그때 그떄 할당해주는 방식이다. 각 스레드에게 할당한 작업에 걸리는 시간을 예측할 수 없을 때 사용한다.

멀티스레딩 전

멀티스레딩 후

profile
이유와 방법을 알려주는 메모장 겸 블로그. 블로그 내용에 대한 토의나 질문은 언제나 환영합니다.

0개의 댓글