파이썬 - 스레드 간 통신

안녕하세요, 미래의 파이썬 마법사들! 오늘은 파이썬에서 스레드 간 통신의 흥미로운 세계로 여행을 떠나보겠습니다. 프로그래밍에 새로운 사람이라도 걱정하지 마세요 - 저는 여러분의 친절한 가이드로, 모든 것을 단계별로 설명해 드리겠습니다. 그럼, 뛰어들어보자!

Python - Inter-thread Communication

什么是线程间通信?

자세한 내용을 알아보기 전에, 스레드 간 통신이란 무엇인지 이해해 봅시다. 큰 프로젝트에 참여하는 팀원들처럼 생각해 보세요. 모두 다른 부분을 작업하고 있지만, 때로는 정보를 공유하거나 노력을 조정해야 합니다. 이正是 프로그램의 스레드들이 하는 일이며, 스레드 간 통신은 그들이 서로에게 "대화"를 할 수 있는 방법입니다.

이벤트 객체

스레드가 통신할 수 있는 가장 간단한 방법으로 이벤트 객체를 시작해 봅시다.

이벤트 객체란 무엇인가?

이벤트 객체는 설정되거나 지워질 수 있는 플래그와 유사합니다. 스레드는 이 플래그가 설정되기를 기다린 후에 진행할 수 있습니다. 이는 거리두기를 기다리는 동안 초록 불이 나타날 때까지 기다리는 것과 유사합니다.

이벤트 객체 사용 방법

간단한 예제를 살펴보겠습니다:

import threading
import time

def waiter(event):
print("Waiter: 이벤트가 설정될 때까지 기다리는 중...")
event.wait()
print("Waiter: 이벤트가 설정되었습니다! 이제 진행할 수 있습니다.")

def setter(event):
print("Setter: 3초 후에 이벤트를 설정하겠습니다...")
time.sleep(3)
event.set()
print("Setter: 이벤트를 설정했습니다!")

# 이벤트 객체 생성
e = threading.Event()

# 스레드 생성 및 시작
t1 = threading.Thread(target=waiter, args=(e,))
t2 = threading.Thread(target=setter, args=(e,))

t1.start()
t2.start()

# 모든 스레드가 끝날 때까지 기다리기
t1.join()
t2.join()

print("Main thread: 모두 완료!")

이를 분석해 봅시다:

  1. threading 모듈을 스레드를 생성하기 위해, time 모듈을 지연을 추가하기 위해 임포트합니다.
  2. 두 개의 함수를 정의합니다: waitersetter.
  3. waiter 함수는 event.wait()를 사용하여 이벤트가 설정될 때까지 기다립니다.
  4. setter 함수는 3초(일부 작업을 시뮬레이션하기 위해) 동안 기다린 후, event.set()를 사용하여 이벤트를 설정합니다.
  5. 이벤트 객체 e를 생성합니다.
  6. 각 함수에 대해 두 개의 스레드를 생성하고, 두 개의 스레드 모두에 이벤트 객체를 전달합니다.
  7. 두 개의 스레드를 시작하고, join()을 사용하여 스레드가 끝날 때까지 기다립니다.

이를 실행하면, waiter가 기다리는 것을 보고, 3초 후 setter가 이벤트를 설정하고, waiter가 진행한다는 것을 볼 수 있습니다.

조건 객체

이제 조건 객체로 한 단계 더 나아가 보겠습니다. 이는 이벤트 객체의 더 복잡한 조카와도 유사합니다.

조건 객체란 무엇인가?

조건 객체는 스레드가 특정 조건이 참이 되기를 기다릴 수 있게 합니다. 이는 파티에서 특정 사람이 도착할 때까지 게임을 시작하지 않는 것과 유사합니다.

조건 객체 사용 방법

조건 객체를 사용하는 예제를 살펴보겠습니다:

import threading
import time
import random

# 공유 자원
items = []
condition = threading.Condition()

def producer():
global items
for i in range(5):
time.sleep(random.random())  # 다양한 생산 시간을 시뮬레이션
with condition:
items.append(f"Item {i}")
print(f"Producer added Item {i}")
condition.notify()  # 소비자에게 아이템이 사용 가능한 것을 알립니다

def consumer():
global items
while True:
with condition:
while not items:
print("Consumer is waiting...")
condition.wait()
item = items.pop(0)
print(f"Consumer removed {item}")
time.sleep(random.random())  # 다양한 소비 시간을 시뮬레이션

# 스레드 생성 및 시작
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

producer_thread.start()
consumer_thread.start()

# 프로듀서가 끝날 때까지 기다리기
producer_thread.join()

# 소비자를 중지(무한 루프에 있음)
consumer_thread.daemon = True

이를 분석해 봅시다:

  1. 공유 자원 items와 조건 객체를 생성합니다.
  2. producer 함수는 아이템을 목록에 추가하고 소비자에게 알립니다.
  3. consumer 함수는 아이템이 사용 가능할 때까지 기다린 후, 아이템을 제거하고 "소비"합니다.
  4. with condition:를 사용하여 조건의 잠금을 자동으로 획득하고 해제합니다.
  5. condition.wait()는 잠금을 반납하고 알림을 기다립니다.
  6. condition.notify()는 기다리는 스레드 중 하나를 깨웁니다.

이 예제는 고전적인 제조자-소비자 시나리오를 보여줍니다. 하나의 스레드가 아이템을 생산하고 다른 스레드가 소비합니다.

이벤트와 조건 객체 비교

여기 이벤트와 조건 객체의 빠른 비교가 있습니다:

특징 이벤트 조건
목적 간단한 신호传送 복잡한 동기화
상태 이진(설정/해제) 여러 상태가 있을 수 있음
기다리기 스레드가 이벤트가 설정될 때까지 기다림 스레드가 특정 조건이 참이 되기를 기다림
알림 모든 기다리는 스레드에 알림 하나 또는 모든 기다리는 스레드에 알림
사용 사례 간단한 "go/no-go" 시나리오 제조자-소비자 문제, 복잡한 동기화

결론

축하합니다! 여러분은 파이썬에서 스레드 간 통신의 첫 걸음을 내딛었습니다. 우리는 간단한 신호传送을 위한 이벤트 객체와 더 복잡한 동기화 시나리오를 위한 조건 객체를 다루었습니다.

기억해 두세요, 새로운 언어를 배우는 것처럼, 연습이 중요합니다. 이러한 객체를 사용하여 여러분 자신의 프로그램을 작성해 보세요. 아마도 간단한 채팅 시스템을 만들어서 스레드가 다른 사용자를 나타내거나, 이벤트를 사용하여 신호등 시스템을 시뮬레이션할 수 있습니다.

스레드 간 통신이 처음에는 어려울 수 있지만, 시간과 연습이 지나면, 마estro가 오케스트라를 이끌어가는 것처럼 스레드를 연주할 수 있을 것입니다. 계속 코딩하고, 계속 배우며, 가장 중요한 것은 즐기세요!

Credits: Image by storyset