일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 프로젝트
- 10분
- 사이드
- 읽기
- 개발자
- 괜찮음
- FIT XR
- Daily Challenge
- 쓰릴오브파이트
- 3줄정리
- Problem Solving
- Writing
- 만화도
- 스탭퍼
- 월간
- 30분
- leetcode
- 화상영어
- 뭐든
- 잡생각
- 영어원서읽기
- 링피트
- 영어공부
- 운동
- 미드시청
- realclass
- 파비최
- 매일
- English
- 리얼 클래스
- Today
- Total
파비의 매일매일 공부기록
파이썬 동시성 프로그래밍 - #4 스레드 간 동기화 본문
이번장에서는 멀티스레드를 사용할 때의 기본적인 동기화 primitive에 대해 알아본다.
앱의 성능을 높이고자 스레드를 추가하는 것만으로는 충분치 않다.
그러므로 경합 조건 같은 복잡한 경우를 고려하고 코드도 적절하게 작성해야 한다.
스레드 간 동기화
- 철학자의 저녁식사 문제(교착상태) : 5명의 철학자가 둥근 탁자에 앉아서 스파게티를 먹는 문제이다. 5개의 포크가 있으나 스파게티를 먹기 위해서는 2개의 포크를 사용해야 한다. 5명 모두가 전부 왼쪽(혹은 오른쪽) 포크를 사용할 때 문제가 생긴다. 아무도 먹을 수가 없다. 이는 동기화 프리미티브(락)에 의지하는 동시성 시스템을 디자인할 때 발생하는 문제를 나타낸다. 포크는 시스템 자원이고 각 철하자는 프로세스라고 보면 된다.
- 경합 조건 : 시스템의 출력이 제어할 수 없는 이벤트의 연속 및 타이밍에 의지하는 상태를 의미. 은행계좌를 예로 들면, 100만 원을 넣어놨는데 그에 대한 이자 10만 원이 들어온다고 하자. 인출과 입금 프로세스가 다르다고 할 때 이자 10만 원이 계좌에 들어가기 전에 계좌에서 100만 원이 인출된다면, 이자는 지급되지 않을 수 있다. 이를 해결하기 위해 계좌 인출 및 갱신 코드, 입금 및 갱신 코드를 묶어 처리하도록 하며 인출 및 갱신 혹은 입근 및 갱신 시 락을 걸어 다른 프로세스가 실행되지 않게 해결할 수 있다.
- 위험영역 : 공유 자원을 수정하고 이에 접근하는 모든 코드의 위험 영역(critical section)에 대해 알아본다. 위험 영역은 어떠한 경우에서는 한 번에 한 개의 프로세스만 실행 가능하다. 예기치 못한 에러를 찾으려 할 때 위험 영역에 넣어 테스트한다. 파일 시스템 및 생명과 직결되는 시스템에서는 위험영역 테스트가 필요할 수 있다.
공유 자원과 데이터 경합 : 동시성 앱을 구현할 때 경합 조건은 꼭 주의해야 한다. 수정하기 힘든 버그로 이어질 수 있으며 앱에 치명적인 영향을 줄 수 있다.
- join 메서드 : 스레드가 종료될 때까지 부모 스레드가 더 진행되지 않게 막아줌. 자연적으로 종료 상태가 되거나 처리되지 않은 예외 경우를 발생 시킴.
- lock : 다수의 스레드 실행으로 공유 자원에 접근할 때 필요한 메커니즘. 화장실 문을 잠그는 것과 비슷한 동기화 프리미티브로 '락' 및 '언락' 상태가 존재하며 '언락' 상태에서만 '락'을 요청 가능
- R락 : 리엔트런트(한 번 로드하면 여러 가지 메인 루틴에서 자유롭게 사용할 수 있는 구조) 락, R락은 일반적인 락 프리미티브에서 작동하는 동기화 프리미티브. 스레드가 이미 갖고 있다고 여러 번 요청됨. 다른 클래스 메서드에 접근하는 클래스 내의 메서드에 스레드 세이프 접근을 이용할 때 쓸모가 있음. 일반적인 락이 교착상태를 유발할 수 있는 반면, R락은 릴리즈 메커니즘이 존재해서 교착상태가 발생하지 않는다.
- 컨디션 : 다른 스레드의 신호를 기다리는 동기화 프리미티브. 해당 스레드가 실행을 마쳐야만 현재 스레드가 나머지 계산을 수행할 수 있음.
- 세마포어 : 요청 및 릴리즈 호출이 있을 때마다 증감되는 내부 카운터. 초기화된 카운터는 다른 세팅이 없으면 기본적으로 1. 세마포어 카운터는 음수가 될 수 없음.
- 한정된 세마포어 : 현재 값이 초기값을 초과하는지 확인. 초과하지 않으면 ValueError 발생. 대부분의 상황에서 세마포어는 한정된 능력으로부터 자원을 보호. 일반적으로 수많은 사람이 한곳에 집중되거나 특정 작업을 한 번에 수행하는 등 자원 소비를 막고자 할 때 사용됨.
- 이벤트 : 동시적으로 실행되는 여러 스레드 사이의 간단한 통신 형태에 유용. 일반적으로 한 스레드가 다른 스레드의 신호를 받아들일 때 이벤트가 발생. 참/거짓이 가능한 내부 플래그로 구성된 객체가 필수로 존재. 스레드는 이벤트 객체의 상태를 계속 확인하며 언제 어떤 방식으로 플래그 상태를 바꿀지 정함.
- 배리어 : 컨디션 및 세마포어의 복잡한 조합으로 해결된 문제를 처리. 모든 스레드 내의 작업이 스레드 그룹에 의해 생성됐는지 보장하는 중요한 부분. 복잡하고 불필요하게 보일 수 있으나 특정 상황에서는 꼭 필요하고 코드 가독성도 높임.
스레드 관련 용어가 엄청 많이 나온 챕터였다.
몇 개는 이미 익숙했던 용어긴 한데.. 아마 오늘 공부한 것의 반 정도는 까먹지 않을까 싶다 ㅎㅎㅎ
덤으로 테스트해볼 소스도 꽤 많다. (각 용어에 대한 상세한 설명을 위한 example이 있음)
'Study > Python' 카테고리의 다른 글
파이썬 동시성 프로그래밍 - #6 디버깅과 벤치마킹 (0) | 2021.08.13 |
---|---|
파이썬 동시성 프로그래밍 - #5 스레드 간의 통신 (0) | 2021.08.12 |
파이썬 동시성 프로그래밍 - #3 스레드 라이프 (0) | 2021.08.10 |
파이썬 동시성 프로그래밍 - #2 병렬화 (0) | 2021.08.09 |
파이썬 동시성 프로그래밍 - #1 시작하기 (2) | 2021.08.08 |