[Python3] 스레드

Alexandria·2023년 8월 31일
0

Python3 Basic

목록 보기
18/19
post-thumbnail

1. Thread

하나의 프로세스에서 여러 개의 스레드를 생성하고 제어할 수 있으며 스레드는 프로세스 내부의 흐름의 단위로, 병렬성을 통해 작업을 처리할 수 있습니다.

Python에서 스레드를 생성하기 위해서는 threading 모듈을 사용합니다. threading.Thread() 함수를 사용하여 스레드 객체를 생성하고,

start() 메서드를 호출하여 스레드를 실행합니다.

또한, join() 메서드를 호출하여 스레드가 종료될 때까지 대기할 수 있습니다.

import threading

def work(s:int, e:int):
    for i in range(s, e):
        print(f"number : {i}")

print(f"active count : {threading.active_count()}") # 메인 스레드 1개

t1 = threading.Thread(target=work, args=(1, 10))
t1.start()
print(f"active count : {threading.active_count()}") # 메인 스레드와 t1으로 2개
t1.join()
print(f"active count : {threading.active_count()}") # t1 종료로인한 메인 스레드 1개

기본적으로 메인 스레드가 종료되더라도 스레드는 끝까지 동작하지만

메인 스레드가 종료되면 하위 스레드도 종료되게 가능합니다.

import threading

def work(s:int, e:int):
    for i in range(s, e):
        print(f"number : {i}")

t1 = threading.Thread(target=work, args=(1, 1024))
t1.daemon = True
t1.start()

스레드가 수행할 함수의 인자가 한 개만 필요하더라도

다음과 같이 args에 쉼표는 유지하여야 합니다.

import threading

def work(e:int):
    for i in range(e):
        print(f"number : {i}")

t1 = threading.Thread(target=work, args=(10,))
t1.start()
t1.join()

2. Multi Thread

GIL(Global Interpreter Lock)으로 인해 한 번에 하나의 스레드만 파이썬 코드를 실행할 수 있습니다.

CPU-bound 작업에 대해서는 멀티 프로세스를 사용하는 것이 효율적이지만

I/O-bound 작업에 대해서는 멀티 스레드를 사용하는 것이 효율적입니다.

다음과 같이 단일 스레드를 실행해서 수행 시간을 측정하였고 결과는 0.0002초가 소요됐습니다.

import time
import threading

def work(start:int, end:int, total:list):
    _   = 0
    for i in range(start, end):
        _ += i
    total.append(_)

def main():
    result      = []
    thread1     = threading.Thread(target=work, args=(0, 1000, result))
    start_time  = time.time()
    thread1.start()
    thread1.join()
    end_time    = time.time()
    return end_time - start_time

if __name__ == "__main__":
    total_elapsed_time  = [main() for i in range(10**4)]
    print(f"elapsed time : {sum(total_elapsed_time)/len(total_elapsed_time)}")

이번에는 2개의 스레드를 사용하였으므로 단일 스레드보다는 빠르게 수행될 것으로 예상되지만 0.0004초가 걸렸습니다.

즉, CPU-bound 작업에 대해서는 멀티 스레드가 비효율적입니다.

import time
import threading

def work(start:int, end:int, total:list):
    _   = 0
    for i in range(start, end):
        _ += i
    total.append(_)

def main():
    result      = []
    thread1     = threading.Thread(target=work, args=(0, 500, result))
    thread2     = threading.Thread(target=work, args=(500, 1000, result))
    start_time  = time.time()
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    end_time    = time.time()
    return end_time - start_time

if __name__ == "__main__":
    total_elapsed_time  = [main() for i in range(10**4)]
    print(f"elapsed time : {sum(total_elapsed_time)/len(total_elapsed_time)}")

💡 GIL에 의해 한 번에 하나의 스레드만 result에 접근이 가능하기 때문에 2개의 스레드가 생각보다 성능이 안 나옵니다. 또한 스레드 간 스위치가 이루어지는 시간까지 더해져 더욱 오래 걸린 것으로 추측됩니다.

profile
IT 도서관

0개의 댓글