Upload
eunmin-kim
View
1.517
Download
2
Embed Size (px)
Citation preview
동시성�프로그래밍하기�자바보다�좋은�Clojure
�/�김은민
왜�이런�주제를?
• 7가지�동시성�모델
이야기�할�내용
1. 동시에�값�하나를�바꾸는�좋은�방법�-�Atom�
2. 동시에�값�여럿을�바꾸는�좋은�방법�-�Ref�
3. 적은�리소스를�사용해서�동시�작업�간에�타이밍을�맞추는�방법�-�core.async
Atom
1.�동시에�값�하나를�바꾸는�좋은�방법
스레드�안전하지�않은�Counter�코드
????????
스레드�안전하지�않은�Counter�코드
바이트�코드
읽고�-�바꾸고�-�쓰고
스레드�안전한�Counter�코드�???
스레드�안전한�Counter�코드�???
동기화�되지�않으면�메인�메모리에�
쓰여지지�않고�CPU�캐시에�남은��
값이�읽힐�수�있다.
스레드�안전한�Counter�코드
synchronized�(Monitor)
• synchronized는�Tony�Hoare가�고안한�Monitor라는�방식의�동기화�방법이다.�
• 자바의�synchronized는�한번에�하나의�스레드가�접근�하기�위해�락을�사용한다.
락의�문제
• 스레드�경합이�없는�단일�스레드에서�락을�얻고�반납하는�일은�부하다.�
• 락을�얻지�못하고�대기�해야하는�스레드가�많아지면�스레드�전환에�들어가는�비용
이�많아진다.�
• 락은�다양한�활동성�문제(데드락,�라이브락,�소모)를�일으킬�수�있다.
자바�병렬�프로그래밍
‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�데이터의�안정성을�보장하는�방법으로�락을�사용하는�
대신�저수준의�하드웨어에서�제공하는� 비교�후�교환�등의�명령을�사용하는�알고리즘을�다루고�있다.’
병렬�연산을�위한�하드웨어적인�지원
• 현대�프로세서는�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>에서�지원한다.
Atomic�클래스를�사용한�넌블로킹�Counter
newValue를�쓰려고�했는데��
누군가�값을�바꿔�oldValue와�다르면�false!그럼�다시�oldValue를�읽어서�시도한다.
락과�넌블로킹�성능�비교
1.�스래드�경쟁이�심한�경우�
Lock�>�Atomic
2.�스래드�경쟁이�일반�적인�경우�
Lock�<�Atomic
클로저�스레드
클로저의�atom을�이용한�넌블로킹�Counter
클로저의�atom을�이용한�넌블로킹�Counter
클로저의�atom을�이용한�넌블로킹�Counter
Ref
2.�동시에�값�여럿을�바꾸는�좋은�방법
자바�병렬�프로그래밍
‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�
데이터의�안정성을�보장하는�방법으로� 락을�사용하는�대신�…’
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.�
• 구현이�힘들어�자바�예제는�생략합니다.�ㅜㅠ
• 클로저�Ref는�STM을�이용한�MVCC�방식의�트랜잭션�기능�
• 예제�
• checking�계좌에�1만원�
• savings�계좌에�2만원�
• checking�계좌에서�savings�계좌로�100원씩�100번�1만원�보낸다.�
• savings�계좌에서�checking�계좌로�200원씩�100번�2만원�보낸다.�
• 결국�savings�계좌에서�checking�계좌로�1만원�보낸다.
클로저�Ref�예제
클로저�Ref�예제
클로저�Ref�예제
200번이�아니다!�
299번은�재시도�되었다.
core.async
3.�적은�리소스를�사용해서�동시�작업�간에� 타이밍을�맞추는�방법
Latch를�이용한�스레드�동기화
• java.util.concurrent�패키지에�Latch�지원�클래스가�있다.�
• 예제�
• Worker1은�1초에�한번씩�10회�화면에�횟수를�출력한다.�
• Worker2는�기다렸다가�Worker1이�5회가�되면�1초에�한번씩�10회�화면에�횟
수를�출력한다.�
• Worker1과�Worker2는�동시에�시작하지만�Worker2는�Worker1이�5회가�될�
때까지�기다려야�한다.
Latch를�이용한�스레드�동기화�예제�-�Worker1
Latch를�이용한�스레드�동기화�예제�-�Worker2
latch가�0이�될때�까지�블로킹
Latch를�이용한�스레드�동기화�예제�
Future를�이용한�스레드�동기화
• java.util.concurrent�패키지에�Future�관련�클래스가�있다.�
• 예제�
• Worker1은�0부터�9까지�합을�구한다.�
• Worker2는�기다렸다가�Worker1의�결과에�0부터�9까지�합을�더한다.�
• Worker1과�Worker2는�동시에�시작하지만�Worker2는�Worker1이�결과를�줄�
때까지�기다린다.
Future를�이용한�스레드�동기화�-�Worker1
Future를�이용한�스레드�동기화�-�Worker2
Worker1�작업이�끝나고�
결과가�나올�때�까지�블로킹
Future를�이용한�스레드�동기화
클로저�future
@는�Future.get이므로�future가�종료될�때까지�블로킹
클로저�future
클로저�future와�promise
프로그램이�끝나지�않도록�블로킹하며�future가�끝나기를�기다린다.
자바�병렬�프로그래밍
‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�
데이터의�안정성을�보장하는�방법으로�…’
다시�넌블로킹
• future와�promise는�작업을�블로킹�하면서�타이밍을�맞춘다.�
• 스레드가�많이�블로킹되면�대기하는�스레드가�많아져�리소스가�낭비된다.�
• 블로킹�대신�스레드를�종료하고�이벤트를�기다렸다�다시�스레드를�실행하는� 이벤트�방식은�효율적이다.
자바�이벤트�기반�예제
onCreate�스레드는�종료된다.
클릭�이벤트가�발생하면�다음�로직을�실행한다.
하지만�콜백�헬…
core.async
• 클로저�CSP(Communicating�sequential�processes�-�Tony�Hoare�1977)�라이브러리�
• 채널�기반의�동시성�흐름�제어�패턴�
• Go�언어에서�기본�동시성�기능으로�제공
core.async
• 채널
체널에�값이�들어올�때�까지�블로킹
체널에�값을�쓴다
core.async
• 신비스러운�Go�루틴 스레드�풀에서�가져온�스레드에서�
채널에�값이�들어오길�기다리는�이벤트�핸들러를�만들고�스레드�종료
채널에�값이�들어오면��
스레드�풀에서�스레드를�가져와�
x에�값을�설정하고�
다시�채널에�값이�들어오길�기다리는�
이벤트�핸들러를�만들고�스레드�종료�채널에�값이�들어오면��
스레드를�풀에서�가져와서��
y에�값을�설정하고�x와�y를��
더한�값을�출력하고�스레드�종료
core.async
• 논블록킹�방식으로�주어진�웹�페이지의�단어�수�세기
넌블로킹과�순차흐름의�장점을�모두�가질�수�있다.�
대기하는�동안�스레드를�점유하지�않기�때문에�적은�리소스를�
사용하는�효율적인�코드를�작성할�수�있다.
아쉽지만�능력�부족으로�다루지�못한�내용
• 함수형�프로그래밍과�동시성�
• pmap,�reducer,�transducer�…�&�Rx�
• Functional�Reactive�Programing�
• CSP
결론으로�가는�중
• 저수준�언어에서�제공하는�스레드와�락�같은�기본�동시성�기능은� 요즘�같은�멀티�코어�환경에서�많은�노력을�해야�재대로�코드를�작성할�수�있다.�
• java.concurrent�패키지�처럼��동시성�관련�라이브러리를�사용하는�것이�좋다.�
• 하지만�언어의�기본�기능으로�제공되는�편리한�스레드와�락의�유혹에서�벗어나기�
어렵다.�
• 현대�프로그래밍�언어들을�기본�언어�기능으로�훌륭한�동시성�기능을�제공한다.
진짜�결론
• 1958년에�고안된�Lisp(클로저)은�저수준�언어인가?�
• 라이브러리를�사용하는�것보다�언어에서�제공해야�하는�것이�아닌가?�
• Lisp의�s-expression은�시대를�초월한다.
Thanks
(quantum-process�…