-
[Python] threading Condition 알아보기 ( wait, notify )Python 2024. 3. 9. 21:36728x90반응형
- 목차
들어가며.
파이썬은 멀티쓰레딩을 위해서 "thread" 와 "threading" 모듈을 제공합니다.
흔히 "thread" 모듈은 멀티쓰레딩 프로그래밍을 위한 고수준의 API 를 담당하고,
"threading" 모듈은 저수준의 기능을 제공하는 것으로 알려집니다.
이번 글에서는 "threading" 모듈의 Condition 과 관련된 기능을 설명하며, 여러가지 케이스에 대해서 실습을 진행해보도록 합니다.
Condition.
Condition 객체는 여러 Thread 간의 동기화를 제공합니다.
Synchroization 이란 ?
먼저 동기화에 대해서 간단히 알아보겠습니다.
동기화의 의미를 한자로 풀어보면 同期 로 작성되는데요.
이는 같음을 의미하는 "동(同)" 과 시간을 의미하는 "기(期)" 가 합쳐진 표현입니다.
즉, 시간이 같다는 의미이죠.
멀티쓰레딩 관점에서 보면 두 쓰레드가 서로 시간의 순서를 잘 지킴을 뜻합니다.
그럼 시간의 순서를 잘 지킨다는 뜻은 무엇일까요 ?
보통 멀티쓰레딩 상황에서는 공유자원을 활용하는 케이스가 빈번합니다.
하나의 자원을 두개 이상의 쓰레드가 동시에 사용하게 된다면 이는 문제를 야기할 가능성이 생기죠.
예를 들어보겠습니다.
아래의 예시는 1천명의 "customers" 이 "toilet" 이라는 화장실를 사용하는 코드입니다.
toilet 은 List 자료형으로 표현했구요.
toilet 리스트에는 하나의 값만이 존재할 수 있습니다.
import threading toilet = [] customers = list(map(lambda x: f"{x}", range(1, 1001))) def visit_toilet (name: str, toilet=None): toilet.append(name) print(f"\"{toilet}\" is in toilet") toilet.remove(name) print(f"\"{toilet}\" is out toilet") for i in customers: customer_thread = threading.Thread(target=visit_toilet, args=(f"{i}", toilet)) customer_thread.start() import time while True: time.sleep(1000)
위 코드를 실행하게 되면 결과는 대략 아래와 같습니다.
두 명의 사람이 하나의 화장실에 함께 존재하게 됩니다.
이러한 상황은 동기화가 이뤄지지 않는 상태입니다.
"toliet" 이라는 공유자원은 오직 한 명의 "customer" 만이 사용할 수 있고, 순서를 지켜야합니다.
// ..생략 "['29', '45']" is in toilet "['29']" is out toilet "['29', '26']" is in toilet "['29']" is out toilet "['29', '56']" is in toilet // ..생략 "['966', '967']" is in toilet // ..생략 "['987', '988']" is in toilet"['988']" is out toilet // ..생략
threading.Condition
threading.Condition 객체를 통해서 동기화를 적용할 수 있습니다.
이를 위해서 threading.Condition 의 몇가지 함수가 제공됩니다.
각각 wait, notify 입니다.
이러한 함수들은 프로그래밍 언어를 막론하고 두루 사용되는 문법입니다.
wait.
Thread 의 wait 함수는 쓰레드를 대기상태에 머물게 합니다.
대기상태의 쓰레드는 다른 쓰레드가 Wakeup 시켜줄 수 있는데요.
다른 쓰레드에 의해서 Wating -> Wakeup 상태로 바뀌도록 하는 함수가 notify 입니다.
notify.
Thread 모듈의 notify 함수는 Waiting 상태의 임의의 쓰레드 하나를 Waiting 상태에서 해지시켜줍니다.
모든 Waiting 상태의 쓰레드들을 깨우는 함수는 notifyAll 입니다.
아래의 예시에서 처럼 notify 없이 wait 함수만 사용된 Thread 는 대기상태에 머물게 됩니다.
import threading condition = threading.Condition() def test_thread (name): with condition: print(f"{name} is waiting") condition.wait() print(f"{name} is freed") for i in range(1, 11): customer_thread = threading.Thread(target=test_thread, args=(f"{i}",)) customer_thread.start() import time time.sleep(3) print("finished")
< 출력 결과 >
4 is waiting 2 is waiting 10 is waiting 5 is waiting 6 is waiting 9 is waiting 3 is waiting 7 is waiting 8 is waiting 1 is waiting finished
하지만 아래와 같이 notify_all 함수를 통해서 모든 Waiting 상태의 쓰레드들을 Wakeup 시킬 수 있습니다.
import threading condition = threading.Condition() def test_thread (name): with condition: print(f"{name} is waiting") condition.wait() print(f"{name} is freed") for i in range(1, 11): customer_thread = threading.Thread(target=test_thread, args=(f"{i}",)) customer_thread.start() import time time.sleep(3) print("finished") with condition: condition.notify_all() time.sleep(3)
2 is waiting 5 is waiting 1 is waiting 4 is waiting 6 is waiting 10 is waiting 9 is waiting 7 is waiting 3 is waiting 8 is waiting finished 2 is freed 3 is freed 8 is freed 5 is freed 1 is freed 4 is freed 7 is freed 6 is freed 9 is freed 10 is freed
다시 "toilet" 과 "customers" 문제로 돌아와보겠습니다.
"toilet" 과 "customers" 동기화.
아래 프로그램은 "toilet" 과 "customers" 문제에 동기화를 적용시킨 예시입니다.
"toilet" 에 누군가가 있다면 condition.wait 를 통해서 대기 상태로 전환합니다.
그리고 "toilet" 사용을 마친 Thread 는 반드시 notify 하여 대기 중인 쓰레드의 Waiting 상태를 깨워줍니다.
import threading condition = threading.Condition() toilet = [] customers = list(map(lambda x: f"{x}", range(1, 1001))) def visit_toilet (name: str, toilet=None): with condition: # 화장실에 누군가가 있다면 계속 기다림. while toilet: condition.wait() toilet.append(name) print(f"\"{toilet}\" is in toilet") toilet.remove(name) print(f"\"{toilet}\" is out toilet") # 화장실 사용후 탈출 condition.notify() for i in customers: customer_thread = threading.Thread(target=visit_toilet, args=(f"{i}", toilet)) customer_thread.start() import time time.sleep(3)
반응형'Python' 카테고리의 다른 글
[Pandas] DataFrame concat 알아보기 (0) 2024.03.09 [Numpy] Boolean Indexing 알아보기 ( Boolean Mask ) (0) 2024.03.09 [Python] io.BytesIO truncate 알아보기 (0) 2024.02.22 [Pandas] Series CRUD 알아보기 (0) 2024.02.21 [python] datetime 여러 활용법 알아보기 ( datetime, timezone, truncate) (0) 2024.01.10