728x90
소개
둘 이상의 쓰레드가 동일한 데이터를 공유하여 발생하는 문제를 해결하기 위한 동기화 기법에 대해 알아보
겠습니다.
-
세마포어(Semaphore): 공유 자원에 여러 프로세스가 접근하는 것을 막는 것
-
뮤텍스(Mutex): 공유 자원에 여러 쓰레드가 접근하는 것을 막는 것
예제 1
두 쓰레드가 동일 변수에 접근하며, 그 과정에서 에러가 발생하도록 유도된 코드입니다.
결과는 90이 아닌 45
import threading
import time
import random
def run(n):
global total_footprint
for i in range(10):
print(f'{n} {i}')
tmp = total_footprint
time.sleep(0.1)
total_footprint = tmp + i
print(f'* [{n} done]')
if __name__ == '__main__':
lock = threading.Lock()
players = ['rabbit', 'turtle']
total_footprint = 0
t1 = threading.Thread(target=run, args=(players[0],))
t2 = threading.Thread(target=run, args=(players[1],))
t1.start()
t2.start()
t1.join()
t2.join()
print(f'total_footprint: {total_footprint}')
rabbit 0
turtle 0
turtle 1
rabbit 1
turtle 2
rabbit 2
turtle 3
rabbit 3
turtle 4
rabbit 4
turtle 5
rabbit 5
turtle 6
rabbit 6
turtle 7
rabbit 7
turtle 8
rabbit 8
turtle 9
rabbit 9
* [turtle done]
* [rabbit done]
total_footprint: 45
임시 변수에 대입 과정에 딜레이를 주는 것만으로 오류가 발생합니다.
tmp = total_footprint
time.sleep(0.1)
total_footprint = tmp + i
예제 2
동기화를 구현한 코드입니다.
뮤텍스(Lock)를 사용하여 각 쓰레드에 대한 데이터 접근을 통제합니다.
import threading
import time
import random
def run(n):
global total_footprint
for i in range(10):
print(f'{n} {i}')
lock.acquire()
tmp = total_footprint
time.sleep(0.1)
total_footprint = tmp + i
lock.release()
print(f'* [{n} done]')
if __name__ == '__main__':
lock = threading.Lock()
players = ['rabbit', 'turtle']
total_footprint = 0
t1 = threading.Thread(target=run, args=(players[0],))
t2 = threading.Thread(target=run, args=(players[1],))
t1.start()
t2.start()
t1.join()
t2.join()
print(f'total_footprint: {total_footprint}')
rabbit 0
turtle 0
rabbit 1
turtle 1
rabbit 2
turtle 2
rabbit 3
turtle 3
rabbit 4
turtle 4
rabbit 5
turtle 5
rabbit 6
turtle 6
rabbit 7
turtle 7
rabbit 8
turtle 8
rabbit 9
turtle 9
* [rabbit done]
* [turtle done]
total_footprint: 90
사용방법은 데이터를 조작하는 부분 앞 뒤로 acquire() 함수와 release() 함수를 사용하시면 됩니다.
acquire() 가 호출되면 동일 데이터에 접근을 원하는 다른 쓰레드는 대기하며, release() 가 호출되면 다른 쓰레드도 해당 데이터에 선점할 수 있는 기회가 주어집니다.
lock = threading.Lock()
...
lock.acquire()
tmp = total_footprint
time.sleep(0.1)
total_footprint = tmp + i
lock.release()
'Language > Python' 카테고리의 다른 글
파이썬 쓰레드(Thread) 알아보기 - 4 : 쓰레드 동작 순서 제어를 위한 Event (0) | 2020.08.12 |
---|---|
파이썬 쓰레드(Thread) 알아보기 - 3 : 데이터 통신 (0) | 2020.08.12 |
파이썬 쓰레드(Thread) 알아보기 - 1 (0) | 2020.08.12 |
파이썬 엘라스틱서치(Elasticsearch) 연동 -2 : CRUD (0) | 2020.08.11 |
파이썬 엘라스틱서치(Elasticsearch) 연동 -1 : 원격 설정 (0) | 2020.08.11 |