11. 락의 문제
• 스레드 경합이 없는 단일 스레드에서 락을 얻고 반납하는 일은 부하다.
• 락을 얻지 못하고 대기 해야하는 스레드가 많아지면 스레드 전환에 들어가는 비용
이 많아진다.
• 락은 다양한 활동성 문제(데드락, 라이브락, 소모)를 일으킬 수 있다.
12. 자바 병렬 프로그래밍
‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이
넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서
데이터의 안정성을 보장하는 방법으로 락을 사용하는
대신 저수준의 하드웨어에서 제공하는
비교 후 교환 등의 명령을 사용하는 알고리즘을 다루고 있다.’
13. 병렬 연산을 위한 하드웨어적인 지원
• 현대 프로세서는 CAS(Compare-and-swap) 연산을 제공한다.
• x86의 CMPXCHG instruction (ex. CMPXCHG r/m8,r8)
• CAS 연산은 값을 변경하기 위해 기존 값과 새 값을 하나의 명령어로 수행한다.
• 만약 기존 값이 변경 하려는 값과 같으면 새 값으로 바꾼다.
• CAS count, 1, 2 ( 기존 값이 1이면 2로 바꾼다. 그렇지 않으면 아무일도 하지
않는다.)
• 스레드 경쟁이 없다면 CAS 연산은 락을 사용하는 연산 보다 2배 빠르다.
- 자바 병렬 프로그래밍 15장
• 자바는 java.util.Concurrent.atomic 패키지에 AtomicXxx 클래스에서 CAS연산
을 지원한다.
• C는 <stdatomic.h>에서 지원한다.
14. Atomic 클래스를 사용한 넌블로킹 Counter
newValue를 쓰려고 했는데
누군가 값을 바꿔 oldValue와 다르면 false!
그럼 다시 oldValue를 읽어서 시도한다.
15. 락과 넌블로킹 성능 비교
1. 스래드 경쟁이 심한 경우
Lock > Atomic
2. 스래드 경쟁이 일반 적인 경우
Lock < Atomic
21. 자바 병렬 프로그래밍
‘병렬 알고리즘과 관련한 최근 연구 결과를 보면 대부분이
넌블로킹 알고리즘, 즉 여러 스레드가 동작하는 환경에서
데이터의 안정성을 보장하는 방법으로
락을 사용하는 대신 …’
22. MVCC (Multiversion connurrency control)
• Multiversion concurrency control (MCC or MVCC), is a concurrency control
method commonly used by database management systems to provide
concurrent access to the database and in programming languages to
implement transactional memory.
…
MVCC provides point in time consistent views. Read transactions under
MVCC typically use a timestamp or transaction ID to determine what state
of the DB to read, and read these versions of the data. Read and write
transactions are thus isolated from each other without any need for
locking. Writes create a newer version, while concurrent reads access the
older version.
• 구현이 힘들어 자바 예제는 생략합니다. ㅜㅠ
23. • 클로저 Ref는 STM을 이용한 MVCC 방식의 트랜잭션 기능
• 예제
• checking 계좌에 1만원
• savings 계좌에 2만원
• checking 계좌에서 savings 계좌로 100원씩 100번 1만원 보낸다.
• savings 계좌에서 checking 계좌로 200원씩 100번 2만원 보낸다.
• 결국 savings 계좌에서 checking 계좌로 1만원 보낸다.
클로저 Ref 예제
27. Latch를 이용한 스레드 동기화
• java.util.concurrent 패키지에 Latch 지원 클래스가 있다.
• 예제
• Worker1은 1초에 한번씩 10회 화면에 횟수를 출력한다.
• Worker2는 기다렸다가 Worker1이 5회가 되면 1초에 한번씩 10회 화면에 횟
수를 출력한다.
• Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 5회가 될
때까지 기다려야 한다.
31. Future를 이용한 스레드 동기화
• java.util.concurrent 패키지에 Future 관련 클래스가 있다.
• 예제
• Worker1은 0부터 9까지 합을 구한다.
• Worker2는 기다렸다가 Worker1의 결과에 0부터 9까지 합을 더한다.
• Worker1과 Worker2는 동시에 시작하지만 Worker2는 Worker1이 결과를 줄
때까지 기다린다.
44. core.async
• 신비스러운 Go 루틴 스레드 풀에서 가져온 스레드에서
채널에 값이 들어오길 기다리는
이벤트 핸들러를 만들고 스레드 종료
채널에 값이 들어오면
스레드 풀에서 스레드를 가져와
x에 값을 설정하고
다시 채널에 값이 들어오길 기다리는
이벤트 핸들러를 만들고 스레드 종료채널에 값이 들어오면
스레드를 풀에서 가져와서
y에 값을 설정하고 x와 y를
더한 값을 출력하고 스레드 종료
45. core.async
• 논블록킹 방식으로 주어진 웹 페이지의 단어 수 세기
넌블로킹과 순차흐름의 장점을 모두 가질 수 있다.
대기하는 동안 스레드를 점유하지 않기 때문에 적은 리소스를
사용하는 효율적인 코드를 작성할 수 있다.
46. 아쉽지만 능력 부족으로 다루지 못한 내용
• 함수형 프로그래밍과 동시성
• pmap, reducer, transducer … & Rx
• Functional Reactive Programing
• CSP
47. 결론으로 가는 중
• 저수준 언어에서 제공하는 스레드와 락 같은 기본 동시성 기능은
요즘 같은 멀티 코어 환경에서 많은 노력을 해야 재대로 코드를 작성할 수 있다.
• java.concurrent 패키지 처럼 동시성 관련 라이브러리를 사용하는 것이 좋다.
• 하지만 언어의 기본 기능으로 제공되는 편리한 스레드와 락의 유혹에서 벗어나기
어렵다.
• 현대 프로그래밍 언어들을 기본 언어 기능으로 훌륭한 동시성 기능을 제공한다.
48. 진짜 결론
• 1958년에 고안된 Lisp(클로저)은 저수준 언어인가?
• 라이브러리를 사용하는 것보다 언어에서 제공해야 하는 것이 아닌가?
• Lisp의 s-expression은 시대를 초월한다.