49
동시성 프로그래밍하기 자바보다 좋은 Clojure / 김은민

동시성 프로그래밍 하기 좋은 Clojure

Embed Size (px)

Citation preview

Page 1: 동시성 프로그래밍 하기 좋은 Clojure

동시성�프로그래밍하기�자바보다�좋은�Clojure

�/�김은민

Page 2: 동시성 프로그래밍 하기 좋은 Clojure

왜�이런�주제를?

• 7가지�동시성�모델

Page 3: 동시성 프로그래밍 하기 좋은 Clojure

이야기�할�내용

1. 동시에�값�하나를�바꾸는�좋은�방법�-�Atom�

2. 동시에�값�여럿을�바꾸는�좋은�방법�-�Ref�

3. 적은�리소스를�사용해서�동시�작업�간에�타이밍을�맞추는�방법�-�core.async

Page 4: 동시성 프로그래밍 하기 좋은 Clojure

Atom

1.�동시에�값�하나를�바꾸는�좋은�방법

Page 5: 동시성 프로그래밍 하기 좋은 Clojure

스레드�안전하지�않은�Counter�코드

????????

Page 6: 동시성 프로그래밍 하기 좋은 Clojure

스레드�안전하지�않은�Counter�코드

바이트�코드

읽고�-�바꾸고�-�쓰고

Page 7: 동시성 프로그래밍 하기 좋은 Clojure

스레드�안전한�Counter�코드�???

Page 8: 동시성 프로그래밍 하기 좋은 Clojure

스레드�안전한�Counter�코드�???

동기화�되지�않으면�메인�메모리에�

쓰여지지�않고�CPU�캐시에�남은��

값이�읽힐�수�있다.

Page 9: 동시성 프로그래밍 하기 좋은 Clojure

스레드�안전한�Counter�코드

Page 10: 동시성 프로그래밍 하기 좋은 Clojure

synchronized�(Monitor)

• synchronized는�Tony�Hoare가�고안한�Monitor라는�방식의�동기화�방법이다.�

• 자바의�synchronized는�한번에�하나의�스레드가�접근�하기�위해�락을�사용한다.

Page 11: 동시성 프로그래밍 하기 좋은 Clojure

락의�문제

• 스레드�경합이�없는�단일�스레드에서�락을�얻고�반납하는�일은�부하다.�

• 락을�얻지�못하고�대기�해야하는�스레드가�많아지면�스레드�전환에�들어가는�비용

이�많아진다.�

• 락은�다양한�활동성�문제(데드락,�라이브락,�소모)를�일으킬�수�있다.

Page 12: 동시성 프로그래밍 하기 좋은 Clojure

자바�병렬�프로그래밍

‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�데이터의�안정성을�보장하는�방법으로�락을�사용하는�

대신�저수준의�하드웨어에서�제공하는� 비교�후�교환�등의�명령을�사용하는�알고리즘을�다루고�있다.’

Page 13: 동시성 프로그래밍 하기 좋은 Clojure

병렬�연산을�위한�하드웨어적인�지원

• 현대�프로세서는�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>에서�지원한다.

Page 14: 동시성 프로그래밍 하기 좋은 Clojure

Atomic�클래스를�사용한�넌블로킹�Counter

newValue를�쓰려고�했는데��

누군가�값을�바꿔�oldValue와�다르면�false!그럼�다시�oldValue를�읽어서�시도한다.

Page 15: 동시성 프로그래밍 하기 좋은 Clojure

락과�넌블로킹�성능�비교

1.�스래드�경쟁이�심한�경우�

Lock�>�Atomic

2.�스래드�경쟁이�일반�적인�경우�

Lock�<�Atomic

Page 16: 동시성 프로그래밍 하기 좋은 Clojure

클로저�스레드

Page 17: 동시성 프로그래밍 하기 좋은 Clojure

클로저의�atom을�이용한�넌블로킹�Counter

Page 18: 동시성 프로그래밍 하기 좋은 Clojure

클로저의�atom을�이용한�넌블로킹�Counter

Page 19: 동시성 프로그래밍 하기 좋은 Clojure

클로저의�atom을�이용한�넌블로킹�Counter

Page 20: 동시성 프로그래밍 하기 좋은 Clojure

Ref

2.�동시에�값�여럿을�바꾸는�좋은�방법

Page 21: 동시성 프로그래밍 하기 좋은 Clojure

자바�병렬�프로그래밍

‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�

데이터의�안정성을�보장하는�방법으로� 락을�사용하는�대신�…’

Page 22: 동시성 프로그래밍 하기 좋은 Clojure

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.�

• 구현이�힘들어�자바�예제는�생략합니다.�ㅜㅠ

Page 23: 동시성 프로그래밍 하기 좋은 Clojure

• 클로저�Ref는�STM을�이용한�MVCC�방식의�트랜잭션�기능�

• 예제�

• checking�계좌에�1만원�

• savings�계좌에�2만원�

• checking�계좌에서�savings�계좌로�100원씩�100번�1만원�보낸다.�

• savings�계좌에서�checking�계좌로�200원씩�100번�2만원�보낸다.�

• 결국�savings�계좌에서�checking�계좌로�1만원�보낸다.

클로저�Ref�예제

Page 24: 동시성 프로그래밍 하기 좋은 Clojure

클로저�Ref�예제

Page 25: 동시성 프로그래밍 하기 좋은 Clojure

클로저�Ref�예제

200번이�아니다!�

299번은�재시도�되었다.

Page 26: 동시성 프로그래밍 하기 좋은 Clojure

core.async

3.�적은�리소스를�사용해서�동시�작업�간에� 타이밍을�맞추는�방법

Page 27: 동시성 프로그래밍 하기 좋은 Clojure

Latch를�이용한�스레드�동기화

• java.util.concurrent�패키지에�Latch�지원�클래스가�있다.�

• 예제�

• Worker1은�1초에�한번씩�10회�화면에�횟수를�출력한다.�

• Worker2는�기다렸다가�Worker1이�5회가�되면�1초에�한번씩�10회�화면에�횟

수를�출력한다.�

• Worker1과�Worker2는�동시에�시작하지만�Worker2는�Worker1이�5회가�될�

때까지�기다려야�한다.

Page 28: 동시성 프로그래밍 하기 좋은 Clojure

Latch를�이용한�스레드�동기화�예제�-�Worker1

Page 29: 동시성 프로그래밍 하기 좋은 Clojure

Latch를�이용한�스레드�동기화�예제�-�Worker2

latch가�0이�될때�까지�블로킹

Page 30: 동시성 프로그래밍 하기 좋은 Clojure

Latch를�이용한�스레드�동기화�예제�

Page 31: 동시성 프로그래밍 하기 좋은 Clojure

Future를�이용한�스레드�동기화

• java.util.concurrent�패키지에�Future�관련�클래스가�있다.�

• 예제�

• Worker1은�0부터�9까지�합을�구한다.�

• Worker2는�기다렸다가�Worker1의�결과에�0부터�9까지�합을�더한다.�

• Worker1과�Worker2는�동시에�시작하지만�Worker2는�Worker1이�결과를�줄�

때까지�기다린다.

Page 32: 동시성 프로그래밍 하기 좋은 Clojure

Future를�이용한�스레드�동기화�-�Worker1

Page 33: 동시성 프로그래밍 하기 좋은 Clojure

Future를�이용한�스레드�동기화�-�Worker2

Worker1�작업이�끝나고�

결과가�나올�때�까지�블로킹

Page 34: 동시성 프로그래밍 하기 좋은 Clojure

Future를�이용한�스레드�동기화

Page 35: 동시성 프로그래밍 하기 좋은 Clojure

클로저�future

@는�Future.get이므로�future가�종료될�때까지�블로킹

Page 36: 동시성 프로그래밍 하기 좋은 Clojure

클로저�future

Page 37: 동시성 프로그래밍 하기 좋은 Clojure

클로저�future와�promise

프로그램이�끝나지�않도록�블로킹하며�future가�끝나기를�기다린다.

Page 38: 동시성 프로그래밍 하기 좋은 Clojure

자바�병렬�프로그래밍

‘병렬�알고리즘과�관련한�최근�연구�결과를�보면�대부분이�넌블로킹�알고리즘,�즉�여러�스레드가�동작하는�환경에서�

데이터의�안정성을�보장하는�방법으로�…’

Page 39: 동시성 프로그래밍 하기 좋은 Clojure

다시�넌블로킹

• future와�promise는�작업을�블로킹�하면서�타이밍을�맞춘다.�

• 스레드가�많이�블로킹되면�대기하는�스레드가�많아져�리소스가�낭비된다.�

• 블로킹�대신�스레드를�종료하고�이벤트를�기다렸다�다시�스레드를�실행하는� 이벤트�방식은�효율적이다.

Page 40: 동시성 프로그래밍 하기 좋은 Clojure

자바�이벤트�기반�예제

onCreate�스레드는�종료된다.

클릭�이벤트가�발생하면�다음�로직을�실행한다.

Page 41: 동시성 프로그래밍 하기 좋은 Clojure

하지만�콜백�헬…

Page 42: 동시성 프로그래밍 하기 좋은 Clojure

core.async

• 클로저�CSP(Communicating�sequential�processes�-�Tony�Hoare�1977)�라이브러리�

• 채널�기반의�동시성�흐름�제어�패턴�

• Go�언어에서�기본�동시성�기능으로�제공

Page 43: 동시성 프로그래밍 하기 좋은 Clojure

core.async

• 채널

체널에�값이�들어올�때�까지�블로킹

체널에�값을�쓴다

Page 44: 동시성 프로그래밍 하기 좋은 Clojure

core.async

• 신비스러운�Go�루틴 스레드�풀에서�가져온�스레드에서�

채널에�값이�들어오길�기다리는�이벤트�핸들러를�만들고�스레드�종료

채널에�값이�들어오면��

스레드�풀에서�스레드를�가져와�

x에�값을�설정하고�

다시�채널에�값이�들어오길�기다리는�

이벤트�핸들러를�만들고�스레드�종료�채널에�값이�들어오면��

스레드를�풀에서�가져와서��

y에�값을�설정하고�x와�y를��

더한�값을�출력하고�스레드�종료

Page 45: 동시성 프로그래밍 하기 좋은 Clojure

core.async

• 논블록킹�방식으로�주어진�웹�페이지의�단어�수�세기

넌블로킹과�순차흐름의�장점을�모두�가질�수�있다.�

대기하는�동안�스레드를�점유하지�않기�때문에�적은�리소스를�

사용하는�효율적인�코드를�작성할�수�있다.

Page 46: 동시성 프로그래밍 하기 좋은 Clojure

아쉽지만�능력�부족으로�다루지�못한�내용

• 함수형�프로그래밍과�동시성�

• pmap,�reducer,�transducer�…�&�Rx�

• Functional�Reactive�Programing�

• CSP

Page 47: 동시성 프로그래밍 하기 좋은 Clojure

결론으로�가는�중

• 저수준�언어에서�제공하는�스레드와�락�같은�기본�동시성�기능은� 요즘�같은�멀티�코어�환경에서�많은�노력을�해야�재대로�코드를�작성할�수�있다.�

• java.concurrent�패키지�처럼��동시성�관련�라이브러리를�사용하는�것이�좋다.�

• 하지만�언어의�기본�기능으로�제공되는�편리한�스레드와�락의�유혹에서�벗어나기�

어렵다.�

• 현대�프로그래밍�언어들을�기본�언어�기능으로�훌륭한�동시성�기능을�제공한다.

Page 48: 동시성 프로그래밍 하기 좋은 Clojure

진짜�결론

• 1958년에�고안된�Lisp(클로저)은�저수준�언어인가?�

• 라이브러리를�사용하는�것보다�언어에서�제공해야�하는�것이�아닌가?�

• Lisp의�s-expression은�시대를�초월한다.

Page 49: 동시성 프로그래밍 하기 좋은 Clojure

Thanks

(quantum-process�…