Python의 threading
모듈로 병렬 작업 처리하기
Overview
Python의 threading
모듈은 병렬 작업을 관리하고 동시에 여러 작업을 실행하는 데 도움을 주는 강력한 도구입니다. 멀티스레딩을 통해 동시에 여러 작업을 수행할 수 있으며, 이는 응답성을 향상시키고, 시간 소모를 줄이며, 효율적인 자원 관리를 가능하게 합니다. 이번 설명에서는 threading
모듈의 주요 기능, 사용법, 예제, 자주 발생하는 오류 및 해결 방법에 대해 자세히 알아보겠습니다.
threading
모듈의 기본 개념
Python의 threading
모듈은 멀티스레딩을 지원하는 데 필요한 다양한 클래스와 메서드를 제공합니다. 멀티스레딩은 프로그램이 여러 작업을 동시에 수행할 수 있도록 합니다. 각 스레드는 프로그램 내에서 독립적으로 실행되며, 공유 자원에 접근할 수 있습니다.
기본 사용법
1. Thread
클래스 사용하기
threading.Thread
클래스는 새로운 스레드를 생성하는 가장 기본적인 방법입니다. 스레드를 생성하려면, Thread
클래스의 인스턴스를 만들고, target
인자에 실행할 함수 또는 메서드를 전달합니다.
예제
다음은 간단한 멀티스레딩 예제입니다. 두 개의 스레드를 생성하여 각각 다른 작업을 동시에 실행합니다.
import threading
import time
def print_numbers():
for i in range(1, 6):
print(f"Number: {i}")
time.sleep(1)
def print_letters():
for letter in 'abcde':
print(f"Letter: {letter}")
time.sleep(1)
# 스레드 생성
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)
# 스레드 시작
thread1.start()
thread2.start()
# 스레드가 완료될 때까지 대기
thread1.join()
thread2.join()
print("Both threads have finished execution.")
이 코드에서 print_numbers
함수와 print_letters
함수는 서로 다른 스레드에서 동시에 실행됩니다. start()
메서드를 호출하면 스레드가 실행을 시작하고, join()
메서드는 스레드가 끝날 때까지 기다립니다.
2. Lock
객체 사용하기
멀티스레딩을 사용할 때, 여러 스레드가 동시에 동일한 자원에 접근하면 데이터 경합이 발생할 수 있습니다. 이를 방지하기 위해 Lock
객체를 사용할 수 있습니다.
예제
다음은 Lock
객체를 사용하여 데이터 경합 문제를 해결하는 예제입니다.
import threading
# 공유 자원
shared_resource = 0
lock = threading.Lock()
def increment():
global shared_resource
with lock:
current_value = shared_resource
current_value += 1
shared_resource = current_value
threads = []
for _ in range(1000):
thread = threading.Thread(target=increment)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(f"Final value of shared_resource: {shared_resource}")
이 코드에서는 increment
함수가 공유 자원인 shared_resource
를 수정할 때 Lock
을 사용하여 동기화를 보장합니다. with lock:
문을 사용하면 스레드가 lock
을 얻을 때까지 대기하게 되고, lock
을 얻은 후에는 다른 스레드가 접근하지 못하도록 합니다.
자주 발생하는 오류 및 해결 방법
1. RuntimeError: thread already started
이 오류는 동일한 스레드를 두 번 시작하려고 할 때 발생합니다. 스레드는 한번만 시작할 수 있으며, 이후에는 start()
메서드를 호출할 수 없습니다.
해결 방법
스레드를 재사용하려면, 새로운 Thread
객체를 생성해야 합니다. 예를 들어:
thread1 = threading.Thread(target=my_function)
thread1.start()
thread1.join()
# 새로운 스레드를 생성하여 다시 사용
thread2 = threading.Thread(target=my_function)
thread2.start()
thread2.join()
2. AttributeError: 'Thread' object has no attribute 'join'
이 오류는 Thread
객체가 아닌 다른 객체에서 join()
메서드를 호출할 때 발생합니다. join()
메서드는 Thread
객체에만 사용할 수 있습니다.
해결 방법
join()
메서드를 호출하기 전에 Thread
객체를 올바르게 생성했는지 확인합니다.
3. GIL(Global Interpreter Lock) 문제
Python은 GIL(Global Interpreter Lock)이라는 개념을 도입하여 한 번에 하나의 스레드만 Python 바이트코드를 실행할 수 있도록 합니다. 이로 인해 CPU 집약적인 작업에서는 멀티스레딩이 성능 향상을 보장하지 않을 수 있습니다.
해결 방법
CPU 집약적인 작업에서는 멀티프로세싱을 사용하는 것이 더 효과적입니다. multiprocessing
모듈을 사용하여 각 프로세스가 독립적으로 실행되도록 할 수 있습니다.
import multiprocessing
def cpu_bound_task():
# CPU 집약적인 작업
pass
processes = []
for _ in range(multiprocessing.cpu_count()):
process = multiprocessing.Process(target=cpu_bound_task)
processes.append(process)
process.start()
for process in processes:
process.join()
참고문서
'Study Information Technology' 카테고리의 다른 글
Python의 collections 모듈 deque와 Counter로 데이터 관리 개선하기 (1) | 2024.08.18 |
---|---|
Python의 pdb 모듈로 인터랙티브 디버깅하기 (1) | 2024.08.18 |
Python의 functools 모듈과 lrucache를 활용한 고차 함수 최적화 (0) | 2024.08.18 |
Python의 asyncio를 활용한 비동기 IO 작업 이해하기 (0) | 2024.08.18 |
Python의 time 및 datetime 모듈로 시간 조작과 스케줄링 수행하기 (0) | 2024.08.18 |