파이썬에서는 메인 스레드에서 발생한 예외가 자동으로 다른 자식 스레드에게 전달되지 않습니다.
명시적으로 이를 전달하거나 통신하는 메커니즘을 사용해야 합니다.
이벤트 플래그
나 큐
와 같은 메커니즘을 사용할 수 있습니다.메인 스레드가 아래를 통해 thread를 생성(fork)한다.
Thread(name=, target=, args= , kwargs= , *, daemon=)
import threading
import time
from typing import List
shared_number = 0
lock = threading.Lock() # threading에서 Lock 함수 가져오기
def thread_1(number: int) -> None:
"""
주어진 수만큼 shared_number를 증가시킵니다.
Args:
number (int): 증가시킬 수
"""
global shared_number
print("number =", end=""), print(number)
lock.acquire() # 작업이 끝나기 전까지 다른 쓰레드가 공유데이터 접근을 금지
for i in range(number):
shared_number += 1
lock.release() # lock 해제
def thread_2(number: int) -> None:
"""
주어진 수만큼 shared_number를 증가시킵니다.
Args:
number (int): 증가시킬 수
"""
global shared_number
print("number =", end=""), print(number)
lock.acquire() # thread_2 잠금
for i in range(number):
shared_number += 1
lock.release() # thread_2 해제
def main() -> None:
"""
두 개의 스레드를 생성하여 동시에 실행합니다.
각 스레드는 shared_number를 주어진 수만큼 증가시킵니다.
실행 시간을 출력하고 최종 shared_number 값을 출력합니다.
"""
global shared_number
threads: List[threading.Thread] = []
start_time = time.time()
t1 = threading.Thread(target=thread_1, args=(50000000,))
t1.start()
threads.append(t1)
t2 = threading.Thread(target=thread_2, args=(50000000,))
t2.start()
threads.append(t2)
for t in threads:
t.join()
print("--- %s seconds ---" % (time.time() - start_time))
print("shared_number=", end=""), print(shared_number)
print("end of main")
if __name__ == "__main__":
main()
import threading
import glob
import time
from typing import List
sema = threading.Semaphore(10)
def copy_from(source: str) -> None:
"""
주어진 파일을 복사하여 'copied_csv' 폴더에 저장합니다.
Args:
source (str): 원본 파일 경로
"""
target = "copied_csv/{}".format(source.split("/")[-1])
sema.acquire()
time.sleep(2)
print("copy ({})".format(source))
with open(source, "r") as rf:
with open(target, "w") as wf:
wf.write(rf.read())
sema.release()
def parallel_copy(source_path: str) -> None:
"""
주어진 경로에 있는 모든 파일을 병렬로 복사합니다.
Args:
source_path (str): 복사할 파일들이 있는 경로 (글로벌 패턴)
"""
thread_list: List[threading.Thread] = [threading.Thread(target=copy_from, args=(source,)) for source in glob.glob(source_path)]
for thread in thread_list:
thread.start()
for thread in thread_list:
thread.join()
def main() -> None:
"""
주어진 경로의 모든 파일을 병렬로 복사하고 실행 시간을 출력합니다.
"""
source_path = "source_csv/*"
start = time.time()
parallel_copy(source_path)
print(time.time() - start)
if __name__ == "__main__":
main()
threading.Event
객체는 Python에서 멀티쓰레딩 환경에서 스레드 간의 신호를 주고받기 위한 동기화 프리미티브 Event
객체는 내부적으로 불리언 플래그를 유지하며, 플래그가 설정(set)되었는지 여부를 스레드들이 확인하고 대기할 수 있습니다. threading.Event
객체의 사용 목적스레드 간의 신호 전달:
Event
객체를 사용하여 하나의 스레드가 다른 스레드에게 신호를 보낼 수 있습니다.동기화:
Event
객체의 상태가 설정되면(set) 대기 중인 모든 스레드가 깨어나 실행을 재개합니다.상태 플래그 관리:
Event
객체는 상태 플래그를 설정(set), 리셋(reset), 대기(wait)하는 메서드를 제공합니다.threading.Event
객체의 주요 메서드set()
: 이벤트 플래그를 True로 설정하여 모든 대기 중인 스레드를 깨웁니다.clear()
: 이벤트 플래그를 False로 설정wait(timeout=None)
: 이벤트 플래그가 True가 될 때까지 대기합니다. 선택적으로 타임아웃을 설정할 수 있습니다.is_set()
: 이벤트 플래그의 현재 상태를 반환합니다.threading.Event
사용 예시import threading
import time
from typing import List
# Event 객체 생성
event: threading.Event = threading.Event()
def worker(event: threading.Event, worker_id: int) -> None:
print(f"Worker {worker_id} waiting for event to be set")
event.wait() # 이벤트가 설정될 때까지 대기
print(f"Worker {worker_id} event received, starting work")
# 스레드 생성
threads: List[threading.Thread] = []
for i in range(3):
thread: threading.Thread = threading.Thread(target=worker, args=(event, i))
threads.append(thread)
thread.start()
time.sleep(2)
print("Main thread setting event")
event.set() # 이벤트 설정
# 모든 스레드가 종료될 때까지 대기
for thread in threads:
thread.join()
print("All workers have finished")
Event
객체를 여러 스레드에서 공유해서 사용하는 경우Event
객체를 여러 스레드에서 공유하여 사용하는 것이 가능 Event
객체의 주요 사용 사례 중 하나Event
객체를 대기하다가, 특정 시점에 메인 스레드나 다른 스레드에서 이벤트를 설정(set)하면 모든 대기 중인 스레드가 깨어나서 작업을 시작하게 됩니다.