์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ Clojure์˜ ํŠธ๋žœ์žญ์…˜ ๋ฉ”๋ชจ๋ฆฌ: ๋™์‹œ์„ฑ ์ œ์–ด์˜ ์ƒˆ๋กœ์šด ํŒจ๋Ÿฌ๋‹ค์ž„

๐Ÿš€ Clojure์˜ ํŠธ๋žœ์žญ์…˜ ๋ฉ”๋ชจ๋ฆฌ: ๋™์‹œ์„ฑ ์ œ์–ด์˜ ์ƒˆ๋กœ์šด ํŒจ๋Ÿฌ๋‹ค์ž„

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ์„ ์‚ฌํ•˜๋Š” ๋™์‹œ์„ฑ์˜ ๋งˆ๋ฒ• โœจ

๐ŸŽฏ ์™œ ๋™์‹œ์„ฑ ์ œ์–ด๊ฐ€ ์ด๋ ‡๊ฒŒ ์–ด๋ ค์šด ๊ฑธ๊นŒ?

์—ฌ๋Ÿฌ๋ถ„, ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ •๋ง ๊ณจ์น˜ ์•„ํ”ˆ ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ๋™์‹œ์„ฑ ์ œ์–ด์˜ˆ์š”. ๐Ÿ˜ซ

์ƒ์ƒํ•ด๋ณด์„ธ์š”. ์€ํ–‰ ๊ณ„์ขŒ์—์„œ ๋ˆ์„ ์ธ์ถœํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, ๋‘ ๊ฐœ์˜ ATM์—์„œ ๋™์‹œ์— ๊ฐ™์€ ๊ณ„์ขŒ์˜ ๋ˆ์„ ๋นผ๋‚ด๋ ค๊ณ  ํ•œ๋‹ค๋ฉด? ์•„๋‹ˆ๋ฉด ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด? ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฑด ์ •๋ง ๊นŒ๋‹ค๋กœ์šด ์ผ์ด์ฃ .

์ „ํ†ต์ ์ธ ๋ฐฉ์‹์—์„œ๋Š” ๋ฝ(Lock)์ด๋‚˜ ๋ฎคํ…์Šค(Mutex)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์–ด์š”. ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•๋“ค์€ ๋ฐ๋“œ๋ฝ(Deadlock), ๋ ˆ์ด์Šค ์ปจ๋””์…˜(Race Condition) ๊ฐ™์€ ์ƒˆ๋กœ์šด ๋ฌธ์ œ๋“ค์„ ๋งŒ๋“ค์–ด๋‚ด๊ณค ํ–ˆ์ฃ . ๐Ÿ”’

๐Ÿ’ก ์ „ํ†ต์ ์ธ ๋™์‹œ์„ฑ ์ œ์–ด์˜ ๋ฌธ์ œ์  โ€ข ๋ฝ์„ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ๋“œ๋ฝ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
โ€ข ์„ฑ๋Šฅ ์ €ํ•˜ (๋ฝ ๋Œ€๊ธฐ ์‹œ๊ฐ„)
โ€ข ์ฝ”๋“œ ๋ณต์žก๋„ ์ฆ๊ฐ€
โ€ข ๋””๋ฒ„๊น…์ด ๋งค์šฐ ์–ด๋ ค์›€
โ€ข ํ™•์žฅ์„ฑ ์ œํ•œ

๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ, Clojure๋ผ๋Š” ์–ธ์–ด๊ฐ€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋กœ Software Transactional Memory (STM)์ด๋ผ๋Š” ๊ฐœ๋…์ด์—์š”! ๐ŸŽ‰

๋™์‹œ์„ฑ ์ œ์–ด ํŒจ๋Ÿฌ๋‹ค์ž„ ๋น„๊ต ์ „ํ†ต์  Lock ๋ฐฉ์‹ ๐Ÿ”’ ์Šค๋ ˆ๋“œ A ๋Œ€๊ธฐ์ค‘... ์Šค๋ ˆ๋“œ B ๋Œ€๊ธฐ์ค‘... ์Šค๋ ˆ๋“œ C ์‹คํ–‰์ค‘ ์ˆœ์ฐจ์  ์ฒ˜๋ฆฌ / ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ฆ๊ฐ€ Clojure STM ๋ฐฉ์‹ โšก ํŠธ๋žœ์žญ์…˜ A ์‹คํ–‰ ํŠธ๋žœ์žญ์…˜ B ์‹คํ–‰ ํŠธ๋žœ์žญ์…˜ C ์‹คํ–‰ ๋™์‹œ ์‹คํ–‰ / ์ž๋™ ์ถฉ๋Œ ํ•ด๊ฒฐ ํŒจ๋Ÿฌ๋‹ค์ž„ ์ „ํ™˜

๐ŸŒŸ Clojure์™€ STM: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜์„ ๋ฉ”๋ชจ๋ฆฌ๋กœ!

Clojure์˜ STM์€ ์ •๋ง ์ฒœ์žฌ์ ์ธ ์•„์ด๋””์–ด์—์„œ ์ถœ๋ฐœํ–ˆ์–ด์š”. ์—ฌ๋Ÿฌ๋ถ„์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜(Transaction)์ด๋ผ๋Š” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜์ž–์•„์š”? BEGIN, COMMIT, ROLLBACK ๊ฐ™์€ ๊ฒƒ๋“ค ๋ง์ด์—์š”. ๐Ÿ’พ

"์ด ๊ฐœ๋…์„ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์—๋„ ์ ์šฉํ•˜๋ฉด ์–ด๋–จ๊นŒ?"

๋ฐ”๋กœ ์ด๊ฒŒ Clojure STM์˜ ํ•ต์‹ฌ ์ฒ ํ•™์ž…๋‹ˆ๋‹ค! ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜์ฒ˜๋Ÿผ, ๋ฉ”๋ชจ๋ฆฌ ์ƒ์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ๋„ ์›์ž์ (Atomic)์œผ๋กœ, ์ผ๊ด€์„ฑ(Consistent) ์žˆ๊ฒŒ, ๊ฒฉ๋ฆฌ(Isolated)๋˜์–ด, ์ง€์†์ (Durable)์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ž๋Š” ๊ฑฐ์ฃ . ๋„ค, ๋งž์•„์š”. ACID ์†์„ฑ์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์šฉํ•œ ๊ฑฐ์˜ˆ์š”! ๐ŸŽฏ

๐Ÿ“š STM์˜ ํ•ต์‹ฌ ๊ฐœ๋… 1. Ref (์ฐธ์กฐ ํƒ€์ž…)
Clojure์—์„œ STM์œผ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ๋‹ด๋Š” ์ปจํ…Œ์ด๋„ˆ์˜ˆ์š”. ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ ๋‹ฌ๋ฆฌ, Ref๋Š” ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ๋งŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด์š”.

2. dosync (ํŠธ๋žœ์žญ์…˜ ๋ธ”๋ก)
๋ชจ๋“  Ref ๋ณ€๊ฒฝ์€ dosync ๋ธ”๋ก ์•ˆ์—์„œ ์ผ์–ด๋‚˜์•ผ ํ•ด์š”. ์ด ๋ธ”๋ก์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ BEGIN...COMMIT๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜์ฃ .

3. ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด
๋ฝ์„ ๊ฑธ์ง€ ์•Š๊ณ  ์ผ๋‹จ ์‹คํ–‰ํ•˜๊ณ , ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„ํ•ด์š”. ์ด๊ฒŒ STM์˜ ๋งˆ๋ฒ•์ด์—์š”! โœจ

4. MVCC (Multi-Version Concurrency Control)
๊ฐ ํŠธ๋žœ์žญ์…˜์€ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€๋œ ์Šค๋ƒ…์ƒท์„ ๋ณด๊ฒŒ ๋˜๊ณ , ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ์ปค๋ฐ‹ ์‹œ์ ์— ์ ์šฉ๋ผ์š”.

์ด๋Ÿฐ ๋ฐฉ์‹์ด ์™œ ํ˜๋ช…์ ์ด๋ƒ๊ณ ์š”? ์ „ํ†ต์ ์ธ ๋ฝ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋ฝ์„ ๊ด€๋ฆฌํ•ด์•ผ ํ–ˆ์–ด์š”. ์–ด๋–ค ์ˆœ์„œ๋กœ ๋ฝ์„ ๊ฑธ๊ณ , ์–ธ์ œ ํ•ด์ œํ• ์ง€, ๋ฐ๋“œ๋ฝ์€ ์–ด๋–ป๊ฒŒ ํ”ผํ• ์ง€... ์ •๋ง ๋จธ๋ฆฌ ์•„ํ”ˆ ์ผ์ด์—ˆ์ฃ . ๐Ÿ˜ต

ํ•˜์ง€๋งŒ STM์—์„œ๋Š”? ๊ทธ๋ƒฅ dosync ๋ธ”๋ก ์•ˆ์— ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋! Clojure ๋Ÿฐํƒ€์ž„์ด ์•Œ์•„์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•ด์ค˜์š”. ๋งˆ์น˜ ์ž๋™์ฐจ์˜ ์ž๋™ ๋ณ€์†๊ธฐ์ฒ˜๋Ÿผ, ๋ณต์žกํ•œ ๋‚ด๋ถ€ ๋™์ž‘์€ ์‹œ์Šคํ…œ์ด ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฐœ๋ฐœ์ž๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฑฐ์ฃ ! ๐Ÿš—

๐Ÿ’ป ์‹ค์ „ ์ฝ”๋“œ๋กœ ์ดํ•ดํ•˜๋Š” Clojure STM

์ด๋ก ๋งŒ ๋“ค์œผ๋ฉด ์ข€ ์ถ”์ƒ์ ์ด์ฃ ? ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ ์ดํ•ดํ•ด๋ด์š”! ์€ํ–‰ ๊ณ„์ขŒ ์ด์ฒด๋ผ๋Š” ํด๋ž˜์‹ํ•œ ์˜ˆ์ œ๋กœ ์‹œ์ž‘ํ•ด๋ณผ๊ฒŒ์š”. ๐Ÿฆ

๐Ÿ”น ๊ธฐ๋ณธ์ ์ธ Ref ์ƒ์„ฑ๊ณผ ์‚ฌ์šฉ
; ๋‘ ๊ฐœ์˜ ์€ํ–‰ ๊ณ„์ขŒ๋ฅผ Ref๋กœ ์ƒ์„ฑ
(def account-a (ref 1000))  ; A ๊ณ„์ขŒ: 1000์›
(def account-b (ref 500))   ; B ๊ณ„์ขŒ: 500์›

; ํ˜„์žฌ ์ž”์•ก ํ™•์ธ (์ฝ๊ธฐ๋Š” ํŠธ๋žœ์žญ์…˜ ์—†์ด๋„ ๊ฐ€๋Šฅ)
@account-a  ; => 1000
@account-b  ; => 500

; ๋‹จ์ˆœ ์ž…๊ธˆ (ํŠธ๋žœ์žญ์…˜ ํ•„์š”)
(dosync
  (alter account-a + 100))  ; A ๊ณ„์ขŒ์— 100์› ์ž…๊ธˆ

@account-a  ; => 1100

์—ฌ๊ธฐ์„œ @ ๊ธฐํ˜ธ๋Š” Ref์˜ ํ˜„์žฌ ๊ฐ’์„ ์ฝ๋Š” ์—ญํ• ์„ ํ•ด์š”. alter ํ•จ์ˆ˜๋Š” Ref์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š”๋ฐ, ๋ฐ˜๋“œ์‹œ dosync ๋ธ”๋ก ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. ๐Ÿ”

๐Ÿ”น ๊ณ„์ขŒ ์ด์ฒด: STM์˜ ์ง„๊ฐ€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ
; ๊ณ„์ขŒ ์ด์ฒด ํ•จ์ˆ˜
(defn transfer [from-account to-account amount]
  (dosync
    (alter from-account - amount)  ; ์ถœ๊ธˆ
    (alter to-account + amount)))  ; ์ž…๊ธˆ

; A ๊ณ„์ขŒ์—์„œ B ๊ณ„์ขŒ๋กœ 300์› ์ด์ฒด
(transfer account-a account-b 300)

@account-a  ; => 800
@account-b  ; => 800

์ด ์ฝ”๋“œ์˜ ์•„๋ฆ„๋‹ค์›€์„ ๋ณด์„ธ์š”! ๐Ÿ˜

๋ฝ์„ ๊ฑธ๊ฑฐ๋‚˜ ํ•ด์ œํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์ „ํ˜€ ์—†์–ด์š”. ๊ทธ๋ƒฅ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ์žˆ์ฃ . ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์Šค๋ ˆ๋“œ ์•ˆ์ „(Thread-safe)ํ•ด์š”. ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด๋„ ๋ฌธ์ œ์—†์–ด์š”!

์™œ๋ƒํ•˜๋ฉด dosync ๋ธ”๋ก ์ „์ฒด๊ฐ€ ํ•˜๋‚˜์˜ ์›์ž์  ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”. ๋งŒ์•ฝ ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ ๊ณ„์ขŒ๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค๋ฉด? Clojure๊ฐ€ ์ž๋™์œผ๋กœ ์ด ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•ด์ค˜์š”. ๊ฐœ๋ฐœ์ž๋Š” ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†์–ด์š”! ๐ŸŽ‰

โœ… STM์˜ ์ž๋™ ์žฌ์‹œ๋„ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ํŠธ๋žœ์žญ์…˜์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ Ref๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด, Clojure๋Š” ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•˜๊ณ  ์ž๋™์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•ด์š”. ์ด ๊ณผ์ •์€ ์™„์ „ํžˆ ํˆฌ๋ช…ํ•˜๊ฒŒ ์ผ์–ด๋‚˜์„œ, ๊ฐœ๋ฐœ์ž๋Š” ๋งˆ์น˜ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์ฝ”๋”ฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธํ•˜๊ฒŒ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ์–ด์š”!
๐Ÿ”น ๋” ๋ณต์žกํ•œ ์˜ˆ์ œ: ์—ฌ๋Ÿฌ ๊ณ„์ขŒ ๋™์‹œ ์ฒ˜๋ฆฌ
; ์—ฌ๋Ÿฌ ๊ณ„์ขŒ ์ƒ์„ฑ
(def accounts (vec (repeatedly 10 #(ref 1000))))

; ๋ฌด์ž‘์œ„ ๊ณ„์ขŒ ๊ฐ„ ์ด์ฒด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜
(defn random-transfer []
  (let [from-idx (rand-int 10)
        to-idx (rand-int 10)
        amount (rand-int 100)]
    (when (not= from-idx to-idx)
      (transfer (accounts from-idx) 
                (accounts to-idx) 
                amount))))

; 100๊ฐœ์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— 1000๋ฒˆ์”ฉ ์ด์ฒด ์‹คํ–‰
(defn stress-test []
  (let [threads (repeatedly 100 
                  #(Thread. 
                    (fn [] 
                      (dotimes [_ 1000] 
                        (random-transfer)))))]
    (doseq [t threads] (.start t))
    (doseq [t threads] (.join t))))

; ์ „์ฒด ์ž”์•ก ํ™•์ธ (ํ•ญ์ƒ 10000์ด์–ด์•ผ ํ•จ)
(defn total-balance []
  (reduce + (map deref accounts)))

(stress-test)
(total-balance)  ; => 10000 (ํ•ญ์ƒ!)

์ด ์ฝ”๋“œ๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•œ ํ…Œ์ŠคํŠธ์˜ˆ์š”! 100๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— 10๋งŒ ๋ฒˆ์˜ ์ด์ฒด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ, ์ „์ฒด ์ž”์•ก์€ ํ•ญ์ƒ ์ •ํ™•ํ•˜๊ฒŒ 10000์›์„ ์œ ์ง€ํ•ด์š”. ๐Ÿ’ช

์ „ํ†ต์ ์ธ ๋ฝ ๋ฐฉ์‹์œผ๋กœ ์ด๊ฑธ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด? ๋ฐ๋“œ๋ฝ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๊ณ„์ขŒ ๋ฒˆํ˜ธ ์ˆœ์„œ๋Œ€๋กœ ๋ฝ์„ ๊ฑธ์–ด์•ผ ํ•˜๊ณ , ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋„ ์‹ ๊ฒฝ ์จ์•ผ ํ•˜๊ณ ... ์ฝ”๋“œ๊ฐ€ ๋ช‡ ๋ฐฐ๋Š” ๋ณต์žกํ•ด์งˆ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ STM์—์„œ๋Š”? ๊ทธ๋ƒฅ ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•ด์š”! ๐Ÿ˜Ž

STM ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ๊ณผ์ • ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ dosync ์ง„์ž… ์Šค๋ƒ…์ƒท ์ƒ์„ฑ ํ˜„์žฌ Ref ๊ฐ’๋“ค์˜ ์ผ๊ด€๋œ ๋ทฐ ํ™•๋ณด ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ alter, ref-set ๋“ฑ์œผ๋กœ Ref ๊ฐ’ ๋ณ€๊ฒฝ ์ถฉ๋Œ ๊ฒ€์‚ฌ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜๊ณผ ์ถฉ๋Œ? ์ถฉ๋Œ ๋ฐœ์ƒ ์ž๋™ ์žฌ์‹œ๋„ ์ถฉ๋Œ ์—†์Œ ์ปค๋ฐ‹ ์™„๋ฃŒ! ํ•ต์‹ฌ ํŠน์ง• 1 ์›์ž์„ฑ ๋ณด์žฅ ํŠธ๋žœ์žญ์…˜ ๋‚ด ๋ชจ๋“  ๋ณ€๊ฒฝ์ด ํ•จ๊ป˜ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ํ•จ๊ป˜ ์‹คํŒจ 2 ์ผ๊ด€์„ฑ ์œ ์ง€ ํ•ญ์ƒ ์œ ํšจํ•œ ์ƒํƒœ๋งŒ ๊ด€์ฐฐ ์ค‘๊ฐ„ ์ƒํƒœ๋Š” ์™ธ๋ถ€์— ๋…ธ์ถœ ์•ˆ๋จ 3 ๊ฒฉ๋ฆฌ์„ฑ ์ œ๊ณต ๊ฐ ํŠธ๋žœ์žญ์…˜์€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž„ 4 ์ž๋™ ์žฌ์‹œ๋„ ์ถฉ๋Œ ๋ฐœ์ƒ์‹œ ๋Ÿฐํƒ€์ž„์ด ์ž๋™์œผ๋กœ ์žฌ์‹คํ–‰

๐ŸŽจ STM์˜ ๋‹ค์–‘ํ•œ ์—ฐ์‚ฐ์ž๋“ค

Clojure STM์€ Ref๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํ•จ์ˆ˜๋“ค์„ ์ œ๊ณตํ•ด์š”. ๊ฐ๊ฐ์˜ ํŠน์„ฑ์„ ์ดํ•ดํ•˜๋ฉด ๋” ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ› ๏ธ

๐Ÿ”น alter: ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ณ€๊ฒฝ ํ•จ์ˆ˜
(def counter (ref 0))

(dosync
  (alter counter inc)      ; counter๋ฅผ 1 ์ฆ๊ฐ€
  (alter counter + 10))    ; counter์— 10 ๋”ํ•˜๊ธฐ

@counter  ; => 11

; alter๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ํ˜„์žฌ ๊ฐ’์— ์ ์šฉ
(dosync
  (alter counter (fn [current-value] 
                   (* current-value 2))))

@counter  ; => 22

alter๋Š” Ref์˜ ํ˜„์žฌ ๊ฐ’์„ ์ฝ๊ณ , ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๊ฒฐ๊ณผ๋กœ ์—…๋ฐ์ดํŠธํ•ด์š”. ํŠธ๋žœ์žญ์…˜์ด ์žฌ์‹œ๋„๋  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ถ€์ž‘์šฉ์ด ์—†๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”! ๐ŸŽฏ

โš ๏ธ alter ์‚ฌ์šฉ์‹œ ์ฃผ์˜์‚ฌํ•ญ alter์— ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๋ฐ˜๋“œ์‹œ ์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•ด์š”! ํŒŒ์ผ ์“ฐ๊ธฐ, ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ์ถœ๋ ฅ ๋“ฑ์˜ ๋ถ€์ž‘์šฉ์ด ์žˆ์œผ๋ฉด ์•ˆ ๋ผ์š”. ์™œ๋ƒํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์ด ์žฌ์‹œ๋„๋  ๋•Œ๋งˆ๋‹ค ์ด ํ•จ์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”.
๐Ÿ”น ref-set: ์ง์ ‘ ๊ฐ’ ์„ค์ •
(def status (ref :idle))

(dosync
  (ref-set status :running))  ; ์ง์ ‘ ๊ฐ’์„ ์„ค์ •

@status  ; => :running

; ์กฐ๊ฑด๋ถ€ ์„ค์ •๋„ ๊ฐ€๋Šฅ
(dosync
  (when (= @status :running)
    (ref-set status :completed)))

@status  ; => :completed

ref-set์€ ํ˜„์žฌ ๊ฐ’๊ณผ ์ƒ๊ด€์—†์ด ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ง์ ‘ ์„ค์ •ํ•ด์š”. ์ด์ „ ๊ฐ’์„ ์ฐธ์กฐํ•  ํ•„์š”๊ฐ€ ์—†์„ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ์š”. ๐Ÿ“

๐Ÿ”น commute: ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜์ง€ ์•Š์„ ๋•Œ์˜ ์ตœ์ ํ™”
(def total-requests (ref 0))

; ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์นด์šดํ„ฐ ์ฆ๊ฐ€
(defn handle-request []
  (dosync
    (commute total-requests inc))  ; alter ๋Œ€์‹  commute ์‚ฌ์šฉ
  ; ... ์š”์ฒญ ์ฒ˜๋ฆฌ ๋กœ์ง ...
  )

; commute๋Š” ๊ตํ™˜๋ฒ•์น™์ด ์„ฑ๋ฆฝํ•˜๋Š” ์—ฐ์‚ฐ์— ์‚ฌ์šฉ
; (+ 1 2 3) = (+ 3 2 1) ์ฒ˜๋Ÿผ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์„ ๋•Œ

commute๋Š” STM์˜ ์ˆจ๊ฒจ์ง„ ๋ณด์„์ด์—์š”! ๐Ÿ’Ž

alter๋Š” ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— Ref ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ์žฌ์‹œ๋„ํ•ด์š”. ํ•˜์ง€๋งŒ commute๋Š” ๋” ๊ด€๋Œ€ํ•ด์š”. ์—ฐ์‚ฐ์˜ ์ˆœ์„œ๊ฐ€ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด (๊ตํ™˜๋ฒ•์น™์ด ์„ฑ๋ฆฝํ•œ๋‹ค๋ฉด), ์ถฉ๋Œ๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋ƒฅ ์ง„ํ–‰ํ•ด์š”!

์˜ˆ๋ฅผ ๋“ค์–ด, ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๊ฒฝ์šฐ A ํŠธ๋žœ์žญ์…˜์ด ๋จผ์ € ์ฆ๊ฐ€์‹œํ‚ค๋“  B ํŠธ๋žœ์žญ์…˜์ด ๋จผ์ € ์ฆ๊ฐ€์‹œํ‚ค๋“  ์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ๊ฐ™์ž–์•„์š”? ์ด๋Ÿฐ ๊ฒฝ์šฐ commute๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์žฌ์‹œ๋„๋ฅผ ์ค„์—ฌ์„œ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿš€

๐Ÿ” alter vs commute ์„ฑ๋Šฅ ๋น„๊ต alter ์‚ฌ์šฉ์‹œ:
โ€ข ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ Ref ๊ฐ’ ๊ธฐ๋ก
โ€ข ์ปค๋ฐ‹ ์‹œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
โ€ข ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ์ „์ฒด ํŠธ๋žœ์žญ์…˜ ์žฌ์‹œ๋„
โ€ข ์ •ํ™•ํ•˜์ง€๋งŒ ์ถฉ๋Œ์ด ๋งŽ์œผ๋ฉด ๋А๋ ค์ง

commute ์‚ฌ์šฉ์‹œ:
โ€ข ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ ๊ฐ’ ํ™•์ธ ์•ˆ ํ•จ
โ€ข ์ปค๋ฐ‹ ์‹œ ๋งˆ์ง€๋ง‰์— ์—ฐ์‚ฐ ์ ์šฉ
โ€ข ์ˆœ์„œ๋งŒ ๋ฐ”๋€” ๋ฟ ์žฌ์‹œ๋„ ๋ถˆํ•„์š”
โ€ข ๊ตํ™˜๋ฒ•์น™์ด ์„ฑ๋ฆฝํ•˜๋Š” ์—ฐ์‚ฐ์—์„œ ํ›จ์”ฌ ๋น ๋ฆ„
๐Ÿ”น ensure: ์ฝ๊ธฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ
(def inventory (ref 100))
(def reserved (ref 0))

(defn reserve-items [amount]
  (dosync
    (ensure inventory)  ; inventory ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ์„ ๋ณด์žฅ
    (when (>= @inventory amount)
      (alter reserved + amount)
      true)))

; ensure๋Š” ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” Ref๋„ ํŠธ๋žœ์žญ์…˜ ๊ฒ€์ฆ์— ํฌํ•จ์‹œํ‚ด

ensure๋Š” ํŠน๋ณ„ํ•œ ํ•จ์ˆ˜์˜ˆ์š”. Ref๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ๊ทธ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์„ ๋ณด์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ด์š”. ๐Ÿ”’

์œ„ ์˜ˆ์ œ์—์„œ inventory๋ฅผ ์ฝ์–ด์„œ ์ถฉ๋ถ„ํ•œ์ง€ ํ™•์ธํ•˜์ง€๋งŒ ๋ณ€๊ฒฝํ•˜์ง€๋Š” ์•Š์•„์š”. ํ•˜์ง€๋งŒ ensure๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ, ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋  ๋•Œ inventory ๊ฐ’์ด ์ค‘๊ฐ„์— ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์„ ๋ณด์žฅ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”!

๐Ÿ—๏ธ ์‹ค์ „ ์˜ˆ์ œ: ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ ์žฌ๊ณ  ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

์ด๋ก ๊ณผ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋Š” ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ, ์ด์ œ ์‹ค์ „ ๊ฐ™์€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”? ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์˜ ์žฌ๊ณ  ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ STM์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค! ๐Ÿ›’

; ์ƒํ’ˆ ์ •๋ณด ๊ตฌ์กฐ
(defrecord Product [id name price stock])

; ์ฃผ๋ฌธ ์ •๋ณด ๊ตฌ์กฐ
(defrecord Order [id customer-id items total status])

; ์ƒํ’ˆ ์žฌ๊ณ ๋ฅผ Ref๋กœ ๊ด€๋ฆฌ
(def products 
  (ref {1 (->Product 1 "๋…ธํŠธ๋ถ" 1500000 10)
        2 (->Product 2 "๋งˆ์šฐ์Šค" 30000 50)
        3 (->Product 3 "ํ‚ค๋ณด๋“œ" 80000 30)}))

; ์ฃผ๋ฌธ ๋ชฉ๋ก
(def orders (ref []))

; ์ฃผ๋ฌธ ID ์ƒ์„ฑ๊ธฐ
(def order-id-counter (ref 0))

; ์ƒํ’ˆ ์ฃผ๋ฌธ ํ•จ์ˆ˜
(defn place-order [customer-id items-to-order]
  (dosync
    (let [order-id (alter order-id-counter inc)
          current-products @products
          
          ; ์žฌ๊ณ  ํ™•์ธ
          stock-check (every? 
                        (fn [[product-id quantity]]
                          (>= (get-in current-products 
                                      [product-id :stock]) 
                              quantity))
                        items-to-order)]
      
      (if stock-check
        ; ์žฌ๊ณ ๊ฐ€ ์ถฉ๋ถ„ํ•˜๋ฉด ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ
        (do
          ; ์žฌ๊ณ  ๊ฐ์†Œ
          (doseq [[product-id quantity] items-to-order]
            (alter products 
                   update-in [product-id :stock] 
                   - quantity))
          
          ; ์ด์•ก ๊ณ„์‚ฐ
          (let [total (reduce 
                        (fn [sum [product-id quantity]]
                          (+ sum 
                             (* quantity 
                                (get-in current-products 
                                        [product-id :price]))))
                        0
                        items-to-order)
                
                new-order (->Order order-id 
                                   customer-id 
                                   items-to-order 
                                   total 
                                   :confirmed)]
            
            ; ์ฃผ๋ฌธ ๋ชฉ๋ก์— ์ถ”๊ฐ€
            (alter orders conj new-order)
            {:success true 
             :order new-order 
             :message "์ฃผ๋ฌธ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!"}))
        
        ; ์žฌ๊ณ  ๋ถ€์กฑ
        {:success false 
         :message "์žฌ๊ณ ๊ฐ€ ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค."}))))

; ์ฃผ๋ฌธ ์ทจ์†Œ ํ•จ์ˆ˜
(defn cancel-order [order-id]
  (dosync
    (let [order (first (filter #(= (:id %) order-id) @orders))]
      (if (and order (= (:status order) :confirmed))
        (do
          ; ์žฌ๊ณ  ๋ณต๊ตฌ
          (doseq [[product-id quantity] (:items order)]
            (alter products 
                   update-in [product-id :stock] 
                   + quantity))
          
          ; ์ฃผ๋ฌธ ์ƒํƒœ ๋ณ€๊ฒฝ
          (alter orders 
                 (fn [order-list]
                   (mapv #(if (= (:id %) order-id)
                           (assoc % :status :cancelled)
                           %)
                         order-list)))
          
          {:success true 
           :message "์ฃผ๋ฌธ์ด ์ทจ์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."})
        
        {:success false 
         :message "์ทจ์†Œํ•  ์ˆ˜ ์—†๋Š” ์ฃผ๋ฌธ์ž…๋‹ˆ๋‹ค."}))))

; ์žฌ๊ณ  ์กฐํšŒ
(defn get-stock [product-id]
  (get-in @products [product-id :stock]))

; ์‚ฌ์šฉ ์˜ˆ์ œ
(place-order 1001 {1 2, 2 3})  
; => {:success true, :order {...}, :message "์ฃผ๋ฌธ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!"}

(get-stock 1)  ; => 8 (10์—์„œ 2๊ฐœ ๊ฐ์†Œ)
(get-stock 2)  ; => 47 (50์—์„œ 3๊ฐœ ๊ฐ์†Œ)

; ๋™์‹œ ์ฃผ๋ฌธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
(defn stress-test-orders []
  (let [threads (repeatedly 50
                  #(Thread. 
                    (fn []
                      (dotimes [_ 10]
                        (place-order 
                          (rand-int 1000)
                          {(inc (rand-int 3)) 1})))))]
    (doseq [t threads] (.start t))
    (doseq [t threads] (.join t))))

(stress-test-orders)
; 500๊ฐœ์˜ ๋™์‹œ ์ฃผ๋ฌธ์ด ์™„๋ฒฝํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋จ!

์ด ์ฝ”๋“œ์˜ ๋ฉ‹์ง„ ์ ์„ ๋ณผ๊นŒ์š”? ๐Ÿ˜Ž

1. ์›์ž์„ฑ ๋ณด์žฅ
์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ ์žฌ๊ณ  ํ™•์ธ, ์žฌ๊ณ  ๊ฐ์†Œ, ์ฃผ๋ฌธ ์ƒ์„ฑ์ด ๋ชจ๋‘ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ฒ˜๋ฆฌ๋ผ์š”. ์ค‘๊ฐ„์— ์‹คํŒจํ•˜๋ฉด ๋ชจ๋“  ๋ณ€๊ฒฝ์ด ๋กค๋ฐฑ๋˜์ฃ !

2. ๋™์‹œ์„ฑ ์•ˆ์ „
50๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ฃผ๋ฌธ์„ ๋„ฃ์–ด๋„ ์žฌ๊ณ ๊ฐ€ ๋งˆ์ด๋„ˆ์Šค๊ฐ€ ๋˜๊ฑฐ๋‚˜ ์ค‘๋ณต ์ฃผ๋ฌธ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์š”. STM์ด ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์ค˜์š”!

3. ์ฝ”๋“œ ๊ฐ„๊ฒฐ์„ฑ
๋ฝ ๊ด€๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์ „ํ˜€ ์—†์–ด์š”. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ๊น”๋”ํ•˜๊ฒŒ ํ‘œํ˜„๋˜์–ด ์žˆ์ฃ . ์ด๊ฒŒ ๋ฐ”๋กœ STM์˜ ํž˜์ด์—์š”! ๐Ÿ’ช

4. ๋ฐ๋“œ๋ฝ ๋ถˆ๊ฐ€๋Šฅ
์—ฌ๋Ÿฌ ์ƒํ’ˆ์„ ๋™์‹œ์— ์ฃผ๋ฌธํ•ด๋„ ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์—†์–ด์š”. STM์€ ๋ฝ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ์š”!

๐Ÿ’ก ์‹ค์ „ ํŒ: ํŠธ๋žœ์žญ์…˜ ํฌ๊ธฐ ์กฐ์ ˆ

ํŠธ๋žœ์žญ์…˜์€ ๊ฐ€๋Šฅํ•œ ํ•œ ์ž‘๊ณ  ๋น ๋ฅด๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒŒ ์ข‹์•„์š”. ํŠธ๋žœ์žญ์…˜์ด ๊ธธ์–ด์งˆ์ˆ˜๋ก ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๊ณ , ์žฌ์‹œ๋„ ๋น„์šฉ๋„ ์ปค์ง€๊ฑฐ๋“ ์š”. ๋ณต์žกํ•œ ๊ณ„์‚ฐ์ด๋‚˜ I/O ์ž‘์—…์€ ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ผญ ํ•„์š”ํ•œ ์ƒํƒœ ๋ณ€๊ฒฝ๋งŒ dosync ์•ˆ์— ๋„ฃ์œผ์„ธ์š”!

โšก STM์˜ ์„ฑ๋Šฅ ํŠน์„ฑ๊ณผ ์ตœ์ ํ™”

STM์ด ํŽธ๋ฆฌํ•˜๊ธด ํ•˜์ง€๋งŒ, ์„ฑ๋Šฅ์€ ์–ด๋–จ๊นŒ์š”? ๋ชจ๋“  ๊ธฐ์ˆ ์—๋Š” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์žˆ์œผ๋‹ˆ๊นŒ์š”. STM์˜ ์„ฑ๋Šฅ ํŠน์„ฑ์„ ์ดํ•ดํ•˜๊ณ  ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด์š”! ๐Ÿ“Š

๐Ÿ”น ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด์˜ ์žฅ๋‹จ์ 
์žฅ์  โœ… โ€ข ๋ฝ ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์—†์Œ
์Šค๋ ˆ๋“œ๋“ค์ด ๋ฝ์„ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ๋ธ”๋ก๋˜์ง€ ์•Š์•„์š”. ๋ชจ๋‘๊ฐ€ ๋™์‹œ์— ์ž‘์—…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์ฃ .

โ€ข ๋ฐ๋“œ๋ฝ ๋ถˆ๊ฐ€๋Šฅ
๋ฝ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋‹ˆ ๋ฐ๋“œ๋ฝ์ด ์›์ฒœ์ ์œผ๋กœ ๋ถˆ๊ฐ€๋Šฅํ•ด์š”.

โ€ข ์ปดํฌ์ €๋นŒ๋ฆฌํ‹ฐ(Composability)
์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์„ ์กฐํ•ฉํ•ด์„œ ๋” ํฐ ํŠธ๋žœ์žญ์…˜์„ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›Œ์š”. ๋ฝ ๊ธฐ๋ฐ˜์—์„œ๋Š” ์ด๊ฒŒ ๋งค์šฐ ์–ด๋ ค์›Œ์š”.

โ€ข ์ฝ๊ธฐ ์„ฑ๋Šฅ ์šฐ์ˆ˜
์ฝ๊ธฐ ์ž‘์—…์€ ๋ฝ ์—†์ด ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰๋ผ์š”.
๋‹จ์  โš ๏ธ โ€ข ์“ฐ๊ธฐ ์ถฉ๋Œ ์‹œ ์žฌ์‹œ๋„ ๋น„์šฉ
์ถฉ๋Œ์ด ๋งŽ์œผ๋ฉด ํŠธ๋žœ์žญ์…˜์ด ์—ฌ๋Ÿฌ ๋ฒˆ ์žฌ์‹œ๋„๋˜์–ด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•ด์š”.

โ€ข ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ
MVCC๋ฅผ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ฒ„์ „์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•ด์š”.

โ€ข ๊ธด ํŠธ๋žœ์žญ์…˜์— ๋ถˆ๋ฆฌ
ํŠธ๋žœ์žญ์…˜์ด ๊ธธ์ˆ˜๋ก ์ถฉ๋Œ ํ™•๋ฅ ์ด ๋†’์•„์ ธ์š”.

โ€ข ๋ถ€์ž‘์šฉ ์ œํ•œ
ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ I/O ๊ฐ™์€ ๋ถ€์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์•ˆ ๋ผ์š”.
๐Ÿ”น ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ „๋žต
; โŒ ๋‚˜์œ ์˜ˆ: ํŠธ๋žœ์žญ์…˜์ด ๋„ˆ๋ฌด ๊น€
(defn bad-update [data-ref]
  (dosync
    (Thread/sleep 1000)  ; ๊ธด ์ž‘์—…
    (alter data-ref inc)
    (println "Updated!")  ; ๋ถ€์ž‘์šฉ
    (Thread/sleep 1000))) ; ๋˜ ๊ธด ์ž‘์—…

; โœ… ์ข‹์€ ์˜ˆ: ํŠธ๋žœ์žญ์…˜์€ ์งง๊ฒŒ, ๋ถ€์ž‘์šฉ์€ ๋ฐ–์—์„œ
(defn good-update [data-ref]
  (let [result (dosync
                 (alter data-ref inc)
                 @data-ref)]
    (println "Updated to:" result)  ; ๋ถ€์ž‘์šฉ์€ ๋ฐ–์—์„œ
    result))

; โŒ ๋‚˜์œ ์˜ˆ: ๋ถˆํ•„์š”ํ•˜๊ฒŒ alter ์‚ฌ์šฉ
(def counter (ref 0))

(defn bad-increment []
  (dosync
    (dotimes [_ 1000]
      (alter counter inc))))  ; 1000๋ฒˆ์˜ alter

; โœ… ์ข‹์€ ์˜ˆ: ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌ
(defn good-increment []
  (dosync
    (alter counter + 1000)))  ; ํ•œ ๋ฒˆ์˜ alter

; โœ… ๋” ์ข‹์€ ์˜ˆ: commute ์‚ฌ์šฉ (์ˆœ์„œ ๋ฌด๊ด€ํ•œ ๊ฒฝ์šฐ)
(defn best-increment []
  (dosync
    (commute counter + 1000)))  ; ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ ๊ฐ์†Œ
๐ŸŽฏ STM ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ฒดํฌ๋ฆฌ์ŠคํŠธ 1. ํŠธ๋žœ์žญ์…˜์„ ์งง๊ฒŒ ์œ ์ง€: ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ์ž‘์—…๋งŒ ํฌํ•จ
2. commute ํ™œ์šฉ: ๊ตํ™˜๋ฒ•์น™์ด ์„ฑ๋ฆฝํ•˜๋Š” ์—ฐ์‚ฐ์€ commute ์‚ฌ์šฉ
3. ๋ถ€์ž‘์šฉ ์ œ๊ฑฐ: I/O, ์ถœ๋ ฅ ๋“ฑ์€ ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ
4. ์ฝ๊ธฐ ์ „์šฉ์€ ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ: ๋‹จ์ˆœ ์กฐํšŒ๋Š” @ ์—ฐ์‚ฐ์ž๋งŒ ์‚ฌ์šฉ
5. ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ: ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ๋ณ€๊ฒฝ์„ ํ•˜๋‚˜๋กœ ๋ฌถ๊ธฐ
6. ํ•ซ์ŠคํŒŸ ํšŒํ”ผ: ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ Ref๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋„๋ก
7. ์ ์ ˆํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ: Ref์˜ ๊ฐœ์ˆ˜์™€ ํฌ๊ธฐ ์ตœ์ ํ™”
๐Ÿ”น ๋ฒค์น˜๋งˆํฌ: STM vs ์ „ํ†ต์  ๋ฝ
; STM ๋ฒ„์ „
(def stm-counter (ref 0))

(defn stm-benchmark []
  (time
    (let [threads (repeatedly 10
                    #(Thread.
                       (fn []
                         (dotimes [_ 10000]
                           (dosync
                             (commute stm-counter inc))))))]
      (doseq [t threads] (.start t))
      (doseq [t threads] (.join t)))))

; ์ „ํ†ต์  ๋ฝ ๋ฒ„์ „
(def lock-counter (atom 0))
(def lock (Object.))

(defn lock-benchmark []
  (time
    (let [threads (repeatedly 10
                    #(Thread.
                       (fn []
                         (dotimes [_ 10000]
                           (locking lock
                             (swap! lock-counter inc))))))]
      (doseq [t threads] (.start t))
      (doseq [t threads] (.join t)))))

; ์‹คํ–‰ ๊ฒฐ๊ณผ (์˜ˆ์‹œ)
; STM: "Elapsed time: 245.3 msecs"
; Lock: "Elapsed time: 312.7 msecs"

; ์ถฉ๋Œ์ด ์ ์€ ๊ฒฝ์šฐ STM์ด ๋” ๋น ๋ฆ„!

๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ํฅ๋ฏธ๋กœ์›Œ์š”! ๐Ÿค”

์ถฉ๋Œ์ด ์ ์€ ์ƒํ™ฉ์—์„œ๋Š” STM์ด ์ „ํ†ต์ ์ธ ๋ฝ๋ณด๋‹ค ๋น ๋ฅด๊ฑฐ๋‚˜ ๋น„์Šทํ•ด์š”. ์™œ๋ƒํ•˜๋ฉด ๋ฝ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์—†๊ณ , commute๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์ถฉ๋Œ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”.

ํ•˜์ง€๋งŒ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ Ref๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋“ฑ ์ถฉ๋Œ์ด ๋งŽ์€ ์ƒํ™ฉ์—์„œ๋Š” ์žฌ์‹œ๋„ ๋น„์šฉ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Ÿด ๋•Œ๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์žฌ์„ค๊ณ„ํ•˜๊ฑฐ๋‚˜, ๊ฒฝ์šฐ์— ๋”ฐ๋ผ atom์ด๋‚˜ agent ๊ฐ™์€ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์–ด์š”.

STM ์„ฑ๋Šฅ ํŠน์„ฑ ๊ทธ๋ž˜ํ”„ ๋™์‹œ ํŠธ๋žœ์žญ์…˜ ์ˆ˜ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ 10 50 100 200 500 ์ „ํ†ต์  Lock Clojure STM STM์ด ์œ ๋ฆฌํ•œ ๊ฒฝ์šฐ ์ฝ๊ธฐ ์ž‘์—…์ด ๋งŽ์€ ๊ฒฝ์šฐ ์ถฉ๋Œ์ด ์ ์€ ๊ฒฝ์šฐ ์งง์€ ํŠธ๋žœ์žญ์…˜ ๋ณต์žกํ•œ ์กฐํ•ฉ ๋กœ์ง ๋ฐ๋“œ๋ฝ ํšŒํ”ผ ํ•„์š” ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์“ฐ๊ธฐ ์ถฉ๋Œ์ด ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์ด ๊ธด ๊ฒฝ์šฐ ํ•ซ์ŠคํŒŸ Ref๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

๐Ÿ”„ Clojure์˜ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์™€ ๋น„๊ต

Clojure๋Š” STM ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ๋™์‹œ์„ฑ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•ด์š”. ๊ฐ๊ฐ์˜ ํŠน์„ฑ์„ ์ดํ•ดํ•˜๊ณ  ์ ์žฌ์ ์†Œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด์š”! ๐ŸŽจ

๐Ÿ”น Atom: ๋™๊ธฐ์  ๋…๋ฆฝ ์ƒํƒœ
; Atom์€ ๋‹จ์ผ ๊ฐ’์˜ ๋™๊ธฐ์  ๋ณ€๊ฒฝ์— ์ตœ์ ํ™”
(def counter (atom 0))

; swap!์œผ๋กœ ๊ฐ’ ๋ณ€๊ฒฝ (CAS ๊ธฐ๋ฐ˜)
(swap! counter inc)  ; => 1

; reset!์œผ๋กœ ์ง์ ‘ ์„ค์ •
(reset! counter 100)  ; => 100

; Atom์€ ํŠธ๋žœ์žญ์…˜ ์—†์ด ์‚ฌ์šฉ
; ์—ฌ๋Ÿฌ Atom์„ ์กฐ์œจํ•  ์ˆ˜ ์—†์Œ
(def account-a (atom 1000))
(def account-b (atom 500))

; โŒ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์›์ž์„ฑ ๋ณด์žฅ ์•ˆ ๋จ
(defn bad-transfer [amount]
  (swap! account-a - amount)
  (swap! account-b + amount))
; ์ค‘๊ฐ„์— ์‹คํŒจํ•˜๋ฉด ์ผ๊ด€์„ฑ ๊นจ์ง!

; โœ… ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์กฐ์œจํ•˜๋ ค๋ฉด Ref ์‚ฌ์šฉ

Atom์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ:
โ€ข ๋‹จ์ผ ๊ฐ’๋งŒ ๋ณ€๊ฒฝํ•  ๋•Œ
โ€ข ํŠธ๋žœ์žญ์…˜์ด ํ•„์š” ์—†์„ ๋•Œ
โ€ข ์ตœ๋Œ€ํ•œ ๋น ๋ฅธ ์„ฑ๋Šฅ์ด ํ•„์š”ํ•  ๋•Œ
โ€ข ๋…๋ฆฝ์ ์ธ ์ƒํƒœ ๊ด€๋ฆฌ

Atom์€ Compare-And-Swap(CAS) ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด์„œ STM๋ณด๋‹ค ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ ์–ด์š”. ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ Atom์„ ์กฐ์œจํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ œ์•ฝ์ด ์žˆ์ฃ . ๐Ÿƒ

๐Ÿ”น Agent: ๋น„๋™๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ
; Agent๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒํƒœ ๋ณ€๊ฒฝ
(def logger (agent []))

; send๋กœ ๋น„๋™๊ธฐ ์ž‘์—… ์ „์†ก
(send logger conj "์ฒซ ๋ฒˆ์งธ ๋กœ๊ทธ")
(send logger conj "๋‘ ๋ฒˆ์งธ ๋กœ๊ทธ")

; ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰
@logger  ; => [] (์•„์ง ์‹คํ–‰ ์•ˆ ๋จ)

; ์ž ์‹œ ํ›„...
(Thread/sleep 100)
@logger  ; => ["์ฒซ ๋ฒˆ์งธ ๋กœ๊ทธ" "๋‘ ๋ฒˆ์งธ ๋กœ๊ทธ"]

; send-off๋Š” ๋ธ”๋กœํ‚น ์ž‘์—…์šฉ (๋ณ„๋„ ์Šค๋ ˆ๋“œ ํ’€)
(def file-writer (agent nil))

(send-off file-writer 
  (fn [_]
    (spit "log.txt" "๋กœ๊ทธ ๋‚ด์šฉ")
    nil))

; Agent๋Š” ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ์ง€์›
(set-error-handler! logger
  (fn [agent exception]
    (println "์—๋Ÿฌ ๋ฐœ์ƒ:" exception)))

Agent๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ:
โ€ข ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ
โ€ข I/O ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ
โ€ข ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์–ด์•ผ ํ•  ๋•Œ
โ€ข ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…

Agent๋Š” ์•กํ„ฐ ๋ชจ๋ธ๊ณผ ๋น„์Šทํ•œ ๊ฐœ๋…์ด์—์š”. ๊ฐ Agent๋Š” ์ž์‹ ๋งŒ์˜ ์ž‘์—… ํ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์ˆœ์ฐจ์ ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ด์š”. STM๊ณผ ๋‹ฌ๋ฆฌ ๋ถ€์ž‘์šฉ์ด ์žˆ๋Š” ์ž‘์—…๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ“ฌ

๐Ÿ”น Var: ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๋ฐ”์ธ๋”ฉ
; Var๋Š” ๋™์  ๋ฐ”์ธ๋”ฉ ์ง€์›
(def ^:dynamic *config* {:debug false})

; binding์œผ๋กœ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๊ฐ’ ์„ค์ •
(binding [*config* {:debug true}]
  (println *config*))  ; => {:debug true}

(println *config*)  ; => {:debug false} (์›๋ž˜ ๊ฐ’)

; ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฐ’ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ
(defn worker [id]
  (binding [*config* {:worker-id id}]
    (println "Worker" id "config:" *config*)))

(.start (Thread. #(worker 1)))
(.start (Thread. #(worker 2)))
; ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์ธ *config* ๊ฐ’ ๊ฐ€์ง

Var๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ:
โ€ข ์Šค๋ ˆ๋“œ๋ณ„๋กœ ๋‹ค๋ฅธ ์„ค์ •์ด ํ•„์š”ํ•  ๋•Œ
โ€ข ์ปจํ…์ŠคํŠธ ์ •๋ณด ์ „๋‹ฌ
โ€ข ํ…Œ์ŠคํŠธ์—์„œ ๋ชจํ‚น
โ€ข ์ „์—ญ ์„ค์ •์˜ ์ž„์‹œ ๋ณ€๊ฒฝ

๐ŸŽฏ ๋™์‹œ์„ฑ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ์„ ํƒ ๊ฐ€์ด๋“œ

์ƒํ™ฉ ์ถ”์ฒœ ๋„๊ตฌ ์ด์œ 
์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์กฐ์œจ Ref (STM) ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์›์ž์„ฑ ๋ณด์žฅ
๋‹จ์ผ ๊ฐ’ ๋น ๋ฅธ ๋ณ€๊ฒฝ Atom CAS ๊ธฐ๋ฐ˜์œผ๋กœ ๋น ๋ฆ„
๋น„๋™๊ธฐ ์ž‘์—… Agent ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ฒ˜๋ฆฌ
I/O ์ž‘์—… Agent ๋ถ€์ž‘์šฉ ํ—ˆ์šฉ
์Šค๋ ˆ๋“œ๋ณ„ ์„ค์ • Var ๋™์  ๋ฐ”์ธ๋”ฉ
๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ณต์œ  ์ผ๋ฐ˜ ๊ฐ’ ๋™๊ธฐํ™” ๋ถˆํ•„์š”

๐ŸŒ STM์˜ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์ ์šฉ ๋ถ„์•ผ

์ด๋ก ๊ณผ ์˜ˆ์ œ๋Š” ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ, ์‹ค์ œ๋กœ STM์ด ์–ด๋””์— ์‚ฌ์šฉ๋˜๋Š”์ง€ ์•Œ์•„๋ณผ๊นŒ์š”? ๐Ÿš€

๐Ÿ”น ๊ธˆ์œต ์‹œ์Šคํ…œ

STM์˜ ๊ฐ€์žฅ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ ์šฉ ๋ถ„์•ผ๋Š” ๊ธˆ์œต ์‹œ์Šคํ…œ์ด์—์š”. ๊ณ„์ขŒ ์ด์ฒด, ๊ฑฐ๋ž˜ ์ฒ˜๋ฆฌ, ์ž”์•ก ๊ด€๋ฆฌ ๋“ฑ ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์›์ž์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด ๋งŽ๊ฑฐ๋“ ์š”. ๐Ÿ’ฐ

์ „ํ†ต์ ์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜๊ณผ ์œ ์‚ฌํ•œ ๊ฐœ๋…์ด๋ผ ๊ธˆ์œต ๊ฐœ๋ฐœ์ž๋“ค์ด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ , ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•œ ๋ถ„์•ผ๋ผ STM์˜ ์žฅ์ ์ด ๋น›์„ ๋ฐœํ•ด์š”!

; ์‹ค์‹œ๊ฐ„ ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ ์˜ˆ์ œ
(def trading-accounts (ref {}))
(def order-book (ref {:buy [] :sell []}))
(def trade-history (ref []))

(defn execute-trade [buyer-id seller-id stock amount price]
  (dosync
    ; ๊ตฌ๋งค์ž ์ž”์•ก ํ™•์ธ ๋ฐ ์ฐจ๊ฐ
    (let [buyer-balance (get-in @trading-accounts 
                                 [buyer-id :balance])]
      (when (>= buyer-balance (* amount price))
        ; ๊ฑฐ๋ž˜ ์‹คํ–‰
        (alter trading-accounts 
               update-in [buyer-id :balance] 
               - (* amount price))
        (alter trading-accounts 
               update-in [buyer-id :stocks stock] 
               (fnil + 0) amount)
        
        (alter trading-accounts 
               update-in [seller-id :balance] 
               + (* amount price))
        (alter trading-accounts 
               update-in [seller-id :stocks stock] 
               - amount)
        
        ; ๊ฑฐ๋ž˜ ๊ธฐ๋ก
        (alter trade-history 
               conj {:buyer buyer-id
                     :seller seller-id
                     :stock stock
                     :amount amount
                     :price price
                     :timestamp (System/currentTimeMillis)})
        
        {:success true :message "๊ฑฐ๋ž˜ ์™„๋ฃŒ"}))))
๐Ÿ”น ๊ฒŒ์ž„ ์„œ๋ฒ„

๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ๊ฒŒ์ž„์—์„œ๋„ STM์ด ์œ ์šฉํ•ด์š”! ์—ฌ๋Ÿฌ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋™์‹œ์— ๊ฒŒ์ž„ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์–ด๋ ค์šด๋ฐ, STM์„ ์‚ฌ์šฉํ•˜๋ฉด ๊น”๋”ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด์š”. ๐ŸŽฎ

; ๊ฒŒ์ž„ ์›”๋“œ ์ƒํƒœ ๊ด€๋ฆฌ
(def game-world 
  (ref {:players {}
        :items {}
        :monsters {}}))

(defn pickup-item [player-id item-id]
  (dosync
    (when (contains? (:items @game-world) item-id)
      ; ์•„์ดํ…œ์„ ์›”๋“œ์—์„œ ์ œ๊ฑฐํ•˜๊ณ  ํ”Œ๋ ˆ์ด์–ด์—๊ฒŒ ์ถ”๊ฐ€
      (alter game-world 
             update :items 
             dissoc item-id)
      (alter game-world 
             update-in [:players player-id :inventory] 
             conj item-id)
      {:success true})))

(defn player-attack [attacker-id target-id damage]
  (dosync
    (let [target-hp (get-in @game-world 
                            [:players target-id :hp])]
      (when (and target-hp (> target-hp 0))
        (let [new-hp (max 0 (- target-hp damage))]
          (alter game-world 
                 assoc-in [:players target-id :hp] 
                 new-hp)
          
          ; ์‚ฌ๋ง ์ฒ˜๋ฆฌ
          (when (= new-hp 0)
            (alter game-world 
                   update-in [:players target-id] 
                   assoc :status :dead))
          
          {:success true 
           :new-hp new-hp})))))
๐Ÿ”น ์‹ค์‹œ๊ฐ„ ํ˜‘์—… ๋„๊ตฌ

์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ๋ฌธ์„œ๋ฅผ ํŽธ์ง‘ํ•˜๋Š” ํ˜‘์—… ๋„๊ตฌ์—์„œ๋„ STM์ด ๋น›์„ ๋ฐœํ•ด์š”. Google Docs ๊ฐ™์€ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์„ธ์š”! ๐Ÿ“

; ํ˜‘์—… ๋ฌธ์„œ ํŽธ์ง‘ ์‹œ์Šคํ…œ
(def document (ref {:content ""
                    :version 0
                    :editors #{}}))

(defn edit-document [user-id edit-fn]
  (dosync
    ; ์‚ฌ์šฉ์ž๋ฅผ ํŽธ์ง‘์ž ๋ชฉ๋ก์— ์ถ”๊ฐ€
    (alter document update :editors conj user-id)
    
    ; ๋ฌธ์„œ ๋‚ด์šฉ ๋ณ€๊ฒฝ
    (alter document update :content edit-fn)
    
    ; ๋ฒ„์ „ ์ฆ๊ฐ€
    (alter document update :version inc)
    
    {:version (:version @document)
     :content (:content @document)}))

(defn insert-text [user-id position text]
  (edit-document user-id
    (fn [content]
      (str (subs content 0 position)
           text
           (subs content position)))))

; ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ํŽธ์ง‘ํ•ด๋„ ์•ˆ์ „!
๐Ÿ”น ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ์˜ ํ™œ์šฉ

์žฌ๋Šฅ๋„ท(https://www.jaenung.net) ๊ฐ™์€ ์žฌ๋Šฅ ๊ฑฐ๋ž˜ ํ”Œ๋žซํผ์—์„œ๋„ STM์ด ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ผ ์ˆ˜ ์žˆ์–ด์š”! ๐ŸŒŸ

์˜ˆ๋ฅผ ๋“ค์–ด, ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์žฌ๋Šฅ ์ƒํ’ˆ์„ ๊ตฌ๋งคํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ์žฌ๊ณ  ๊ด€๋ฆฌ์™€ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ๋ฅผ ์›์ž์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜์ž–์•„์š”? ๋˜๋Š” ํฌ์ธํŠธ ์ ๋ฆฝ, ์ฟ ํฐ ์‚ฌ์šฉ, ๋“ฑ๊ธ‰ ์—…๋ฐ์ดํŠธ ๊ฐ™์€ ์—ฌ๋Ÿฌ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์–ด์•ผ ํ•  ๋•Œ๋„ ์žˆ๊ณ ์š”.

; ์žฌ๋Šฅ๋„ท ์Šคํƒ€์ผ์˜ ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ
(def users (ref {}))
(def talents (ref {}))
(def transactions (ref []))

(defn purchase-talent [buyer-id talent-id]
  (dosync
    (let [buyer (get @users buyer-id)
          talent (get @talents talent-id)
          price (:price talent)]
      
      (when (and buyer talent
                 (>= (:points buyer) price)
                 (> (:available talent) 0))
        
        ; ํฌ์ธํŠธ ์ฐจ๊ฐ
        (alter users 
               update-in [buyer-id :points] 
               - price)
        
        ; ์žฌ๋Šฅ ์žฌ๊ณ  ๊ฐ์†Œ
        (alter talents 
               update-in [talent-id :available] 
               dec)
        
        ; ํŒ๋งค์ž์—๊ฒŒ ํฌ์ธํŠธ ์ง€๊ธ‰
        (alter users 
               update-in [(:seller-id talent) :points] 
               + (* price 0.9))  ; 10% ์ˆ˜์ˆ˜๋ฃŒ
        
        ; ๊ฑฐ๋ž˜ ๊ธฐ๋ก
        (alter transactions 
               conj {:buyer buyer-id
                     :talent talent-id
                     :price price
                     :timestamp (System/currentTimeMillis)})
        
        ; ๊ตฌ๋งค ํšŸ์ˆ˜ ์ฆ๊ฐ€๋กœ ๋“ฑ๊ธ‰ ์—…๋ฐ์ดํŠธ
        (alter users 
               update-in [buyer-id :purchase-count] 
               inc)
        
        {:success true 
         :message "์žฌ๋Šฅ ๊ตฌ๋งค ์™„๋ฃŒ!"}))))

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ฐ„๊ฒฐํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋ฝ์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์•„๋„ ๋˜๋‹ˆ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊น”๋”ํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฝ์ฃ ! ๐Ÿ˜Š

๐ŸŽ“ STM ํ•™์Šต ๋กœ๋“œ๋งต๊ณผ ์‹ค์ „ ํŒ

STM์„ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ๊ณต๋ถ€ํ•ด์•ผ ํ• ๊นŒ์š”? ๋‹จ๊ณ„๋ณ„ ํ•™์Šต ๋กœ๋“œ๋งต์„ ์ œ์‹œํ•ด๋“œ๋ฆด๊ฒŒ์š”! ๐Ÿ“š

๐ŸŽฏ ๋‹จ๊ณ„๋ณ„ ํ•™์Šต ๋กœ๋“œ๋งต 1๋‹จ๊ณ„: ๊ธฐ์ดˆ ๋‹ค์ง€๊ธฐ (1-2์ฃผ)
โ€ข Clojure ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ํ•™์Šต
โ€ข ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ดํ•ด
โ€ข ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…
โ€ข ๊ธฐ๋ณธ ๋™์‹œ์„ฑ ๋ฌธ์ œ ์ดํ•ด

2๋‹จ๊ณ„: STM ๊ธฐ๋ณธ (2-3์ฃผ)
โ€ข Ref, dosync ์‚ฌ์šฉ๋ฒ•
โ€ข alter, ref-set ์ฐจ์ด์ 
โ€ข ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ ๊ตฌํ˜„ (์นด์šดํ„ฐ, ๊ณ„์ขŒ ์ด์ฒด)
โ€ข ํŠธ๋žœ์žญ์…˜ ๊ฐœ๋… ์ดํ•ด

3๋‹จ๊ณ„: ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ (3-4์ฃผ)
โ€ข commute ํ™œ์šฉ๋ฒ•
โ€ข ensure ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค
โ€ข ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•
โ€ข ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์™€ ๋น„๊ต

4๋‹จ๊ณ„: ์‹ค์ „ ํ”„๋กœ์ ํŠธ (4์ฃผ ์ด์ƒ)
โ€ข ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„
โ€ข ์„ฑ๋Šฅ ์ธก์ • ๋ฐ ํŠœ๋‹
โ€ข ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐ ๋””๋ฒ„๊น…
โ€ข ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ๊ฒฝํ—˜
๐Ÿ’ก ์‹ค์ „ ๊ฐœ๋ฐœ ํŒ 1. ์ž‘๊ฒŒ ์‹œ์ž‘ํ•˜๊ธฐ
์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณต์žกํ•œ ์‹œ์Šคํ…œ์— STM์„ ์ ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”. ์ž‘์€ ๋ชจ๋“ˆ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๊ฒฝํ—˜์„ ์Œ“์œผ์„ธ์š”.

2. ๋กœ๊น…๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง
ํŠธ๋žœ์žญ์…˜ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”. ์žฌ์‹œ๋„๊ฐ€ ๋งŽ๋‹ค๋ฉด ์„ค๊ณ„๋ฅผ ์žฌ๊ฒ€ํ† ํ•ด์•ผ ํ•ด์š”.

3. ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
๋™์‹œ์„ฑ ๋ฒ„๊ทธ๋Š” ์ฐพ๊ธฐ ์–ด๋ ค์›Œ์š”. ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด์„œ ์ถฉ๋ถ„ํžˆ ๊ฒ€์ฆํ•˜์„ธ์š”.

4. ๋ฌธ์„œํ™”
์–ด๋–ค Ref๊ฐ€ ์–ด๋–ค ํŠธ๋žœ์žญ์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š”์ง€ ๋ช…ํ™•ํžˆ ๋ฌธ์„œํ™”ํ•˜์„ธ์š”.

5. ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ์šฉ
Clojure ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ๋งค์šฐ ํ™œ๋ฐœํ•ด์š”. ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ์งˆ๋ฌธํ•˜์„ธ์š”!
โš ๏ธ ํ”ํ•œ ์‹ค์ˆ˜์™€ ํ•ด๊ฒฐ์ฑ… ์‹ค์ˆ˜ 1: ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ I/O ์ˆ˜ํ–‰
โŒ ๋ฌธ์ œ: ํŒŒ์ผ ์“ฐ๊ธฐ, DB ์ฟผ๋ฆฌ ๋“ฑ์„ dosync ์•ˆ์—์„œ ์ˆ˜ํ–‰
โœ… ํ•ด๊ฒฐ: I/O๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ Agent ์‚ฌ์šฉ

์‹ค์ˆ˜ 2: ๋„ˆ๋ฌด ๊ธด ํŠธ๋žœ์žญ์…˜
โŒ ๋ฌธ์ œ: ๋ณต์žกํ•œ ๊ณ„์‚ฐ์„ ํŠธ๋žœ์žญ์…˜ ์•ˆ์— ํฌํ•จ
โœ… ํ•ด๊ฒฐ: ๊ณ„์‚ฐ์€ ๋ฐ–์—์„œ ํ•˜๊ณ  ๊ฒฐ๊ณผ๋งŒ ํŠธ๋žœ์žญ์…˜์—์„œ ์ ์šฉ

์‹ค์ˆ˜ 3: ๋ชจ๋“  ๊ณณ์— STM ์‚ฌ์šฉ
โŒ ๋ฌธ์ œ: ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ์—๋„ ๋ฌด์กฐ๊ฑด Ref ์‚ฌ์šฉ
โœ… ํ•ด๊ฒฐ: ์ƒํ™ฉ์— ๋งž๋Š” ๋„๊ตฌ ์„ ํƒ (Atom, Agent ๋“ฑ)

์‹ค์ˆ˜ 4: ์žฌ์‹œ๋„ ๋ถ€์ž‘์šฉ ๋ฌด์‹œ
โŒ ๋ฌธ์ œ: ์žฌ์‹œ๋„๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑธ ๊ณ ๋ คํ•˜์ง€ ์•Š์Œ
โœ… ํ•ด๊ฒฐ: ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ๋ถ€์ž‘์šฉ ์ œ๊ฑฐ
STM ๋งˆ์Šคํ„ฐ ๋กœ๋“œ๋งต 1๋‹จ๊ณ„ ๐ŸŽฏ ๊ธฐ์ดˆ ๋‹ค์ง€๊ธฐ Clojure ๋ฌธ๋ฒ• ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๋™์‹œ์„ฑ ๊ฐœ๋… 2๋‹จ๊ณ„ ๐Ÿ“– STM ๊ธฐ๋ณธ Ref์™€ dosync ๊ธฐ๋ณธ ์—ฐ์‚ฐ์ž ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ 3๋‹จ๊ณ„ ๐Ÿš€ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ commute ํ™œ์šฉ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋น„๊ต ๋ถ„์„ 4๋‹จ๊ณ„ ๐Ÿ’ช ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์‹ค์ œ ๊ตฌํ˜„ ์„ฑ๋Šฅ ํŠœ๋‹ ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ํ•™์Šต ๋ฆฌ์†Œ์Šค ์ถ”์ฒœ 1 ๊ณต์‹ ๋ฌธ์„œ Clojure ๊ณต์‹ ๋ ˆํผ๋Ÿฐ์Šค์™€ ๊ฐ€์ด๋“œ 2 ์˜จ๋ผ์ธ ๊ฐ•์˜ Clojure for the Brave and True ๋“ฑ 3 ์‹ค์Šต ํ”„๋กœ์ ํŠธ GitHub์˜ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๋ถ„์„ 4 ์ปค๋ฎค๋‹ˆํ‹ฐ ClojureVerse, Slack ์ฑ„๋„ ์ฐธ์—ฌ 5 ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž์˜ ์ฝ”๋“œ ๋ถ„์„ ๋ฐ ํ”ผ๋“œ๋ฐฑ 6 ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉฐ ๊นŠ์ด ์ดํ•ด

๐Ÿ”ฎ STM์˜ ๋ฏธ๋ž˜์™€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ์˜ ํ™•์‚ฐ

Clojure์˜ STM์€ ์ •๋ง ํ˜์‹ ์ ์ธ ๊ฐœ๋…์ด์—ˆ์–ด์š”. ๊ทธ๋ž˜์„œ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๋„ ์ด ์•„์ด๋””์–ด๋ฅผ ๋ฐ›์•„๋“ค์ด๊ธฐ ์‹œ์ž‘ํ–ˆ์ฃ ! ๐ŸŒŸ

๐Ÿ”น ๋‹ค๋ฅธ ์–ธ์–ด์˜ STM ๊ตฌํ˜„

Haskell
Haskell์€ STM์„ ํƒ€์ž… ์‹œ์Šคํ…œ๊ณผ ๊ฒฐํ•ฉํ•ด์„œ ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์–ด์š”. STM ๋ชจ๋‚˜๋“œ๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜ ์ฝ”๋“œ๋ฅผ ํƒ€์ž… ๋ ˆ๋ฒจ์—์„œ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์ฃ .

Scala
ScalaSTM ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด Clojure์™€ ์œ ์‚ฌํ•œ STM ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์š”. Scala์˜ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ํ•จ์ˆ˜ํ˜• ํŒจ๋Ÿฌ๋‹ค์ž„์„ ๋ชจ๋‘ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

Python
python-stm ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์žˆ์ง€๋งŒ, ๋™์  ํƒ€์ž… ์–ธ์–ด์˜ ํŠน์„ฑ์ƒ ์„ฑ๋Šฅ์ด ์ œํ•œ์ ์ด์—์š”.

Java
Multiverse, Akka STM ๋“ฑ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ Java์˜ ๋ฌธ๋ฒ•์  ์ œ์•ฝ ๋•Œ๋ฌธ์— Clojure๋งŒํผ ์šฐ์•„ํ•˜์ง€๋Š” ์•Š์•„์š”.

๐Ÿ”น STM์˜ ํ•œ๊ณ„์™€ ๋Œ€์•ˆ

STM์ด ์™„๋ฒฝํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์•„๋‹ˆ์—์š”. ๋ช‡ ๊ฐ€์ง€ ํ•œ๊ณ„๊ฐ€ ์žˆ์ฃ :

1. ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์—์„œ์˜ ์ œ์•ฝ
STM์€ ๋‹จ์ผ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ๋งŒ ์ž‘๋™ํ•ด์š”. ์—ฌ๋Ÿฌ ์„œ๋ฒ„์— ๊ฑธ์นœ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ์ง€์›ํ•˜์ง€ ์•Š์•„์š”. ์ด๋Ÿฐ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์ ‘๊ทผ์ด ํ•„์š”ํ•ด์š”.

2. ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ์˜ ์–ด๋ ค์›€
์žฌ์‹œ๋„ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋•Œ๋ฌธ์— ์‹คํ–‰ ์‹œ๊ฐ„์„ ์˜ˆ์ธกํ•˜๊ธฐ ์–ด๋ ค์›Œ์š”. ํ•˜๋“œ ๋ฆฌ์–ผํƒ€์ž„ ์‹œ์Šคํ…œ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด์š”.

3. ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ
MVCC๋ฅผ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ฒ„์ „์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•ด์š”.

4. ํ•™์Šต ๊ณก์„ 
ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๋ถˆ๋ณ€์„ฑ ๊ฐœ๋…์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ์ง„์ž… ์žฅ๋ฒฝ์ด ์žˆ์–ด์š”.

๐ŸŒ ๋™์‹œ์„ฑ ์ œ์–ด ํŒจ๋Ÿฌ๋‹ค์ž„ ๋น„๊ต ๋ฝ ๊ธฐ๋ฐ˜ (์ „ํ†ต์ )
์žฅ์ : ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›€, ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์„ฑ๋Šฅ
๋‹จ์ : ๋ฐ๋“œ๋ฝ, ๋ณต์žกํ•œ ์ฝ”๋“œ, ํ™•์žฅ์„ฑ ์ œํ•œ

STM (Clojure)
์žฅ์ : ์ปดํฌ์ €๋ธ”, ๋ฐ๋“œ๋ฝ ์—†์Œ, ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ
๋‹จ์ : ์žฌ์‹œ๋„ ์˜ค๋ฒ„ํ—ค๋“œ, ๋‹จ์ผ ํ”„๋กœ์„ธ์Šค ์ œํ•œ

์•กํ„ฐ ๋ชจ๋ธ (Erlang, Akka)
์žฅ์ : ๋ถ„์‚ฐ ์‹œ์Šคํ…œ ์ง€์›, ๊ฒฉ๋ฆฌ์„ฑ
๋‹จ์ : ๋ฉ”์‹œ์ง€ ํŒจ์‹ฑ ์˜ค๋ฒ„ํ—ค๋“œ, ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ

CSP (Go, Clojure core.async)
์žฅ์ : ๊ฐ„๋‹จํ•œ ๋™์‹œ์„ฑ ๋ชจ๋ธ, ์ฑ„๋„ ๊ธฐ๋ฐ˜ ํ†ต์‹ 
๋‹จ์ : ๋ฐฑํ”„๋ ˆ์…” ๊ด€๋ฆฌ, ๋ณต์žกํ•œ ์กฐ์œจ

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ (RxJava, Reactor)
์žฅ์ : ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ, ๋ฐฑํ”„๋ ˆ์…”
๋‹จ์ : ํ•™์Šต ๊ณก์„ , ๋””๋ฒ„๊น… ์–ด๋ ค์›€

๊ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์€ ์žฅ๋‹จ์ ์ด ์žˆ์–ด์š”. ์ค‘์š”ํ•œ ๊ฑด ์ƒํ™ฉ์— ๋งž๋Š” ๋„๊ตฌ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฑฐ์˜ˆ์š”! STM์€ ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์กฐ์œจํ•ด์•ผ ํ•˜๋Š” ๋ณต์žกํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ์— ํŠนํžˆ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋ชจ๋“  ์ƒํ™ฉ์˜ ๋งŒ๋Šฅ ํ•ด๊ฒฐ์ฑ…์€ ์•„๋‹ˆ์—์š”. ๐ŸŽฏ

๐Ÿ’ผ ์‹ค๋ฌด์—์„œ STM ๋„์ž…ํ•˜๊ธฐ

์ด๋ก ๊ณผ ์˜ˆ์ œ๋Š” ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— STM์„ ๋„์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ๊นŒ์š”? ๐Ÿš€

๐Ÿ”น ๋„์ž… ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ
โœ… STM ๋„์ž…์„ ๊ณ ๋ คํ•ด์•ผ ํ•  ๋•Œ โ€ข ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์›์ž์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๋•Œ
โ€ข ๋ณต์žกํ•œ ๋™์‹œ์„ฑ ๋กœ์ง์ด ํ•„์š”ํ•  ๋•Œ
โ€ข ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์ด ๋งค์šฐ ์ค‘์š”ํ•  ๋•Œ
โ€ข ๋ฝ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•ด์งˆ ๋•Œ
โ€ข ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์„ ํ˜ธํ•  ๋•Œ
โ€ข ํŒ€์ด Clojure์— ์ต์ˆ™ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์šธ ์˜์ง€๊ฐ€ ์žˆ์„ ๋•Œ
โš ๏ธ STM ๋„์ž…์„ ์žฌ๊ณ ํ•ด์•ผ ํ•  ๋•Œ โ€ข ๋‹จ์ˆœํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ (Atom์œผ๋กœ ์ถฉ๋ถ„)
โ€ข ๋ถ„์‚ฐ ์‹œ์Šคํ…œ (๋‹ค๋ฅธ ์†”๋ฃจ์…˜ ํ•„์š”)
โ€ข ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ (์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์„ฑ๋Šฅ ํ•„์š”)
โ€ข ํŒ€์˜ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฒฝํ—˜ ๋ถ€์กฑ
โ€ข ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ๊ณผ์˜ ํ†ตํ•ฉ์ด ๋ณต์žกํ•  ๋•Œ
โ€ข I/O ์ค‘์‹ฌ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
๐Ÿ”น ๋‹จ๊ณ„์  ๋„์ž… ์ „๋žต

1๋‹จ๊ณ„: ํŒŒ์ผ๋Ÿฟ ํ”„๋กœ์ ํŠธ
์ž‘์€ ๋ชจ๋“ˆ์ด๋‚˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋จผ์ € ์ ์šฉํ•ด๋ณด์„ธ์š”. ์ „์ฒด ์‹œ์Šคํ…œ์„ ํ•œ ๋ฒˆ์— ๋ฐ”๊พธ๋ ค๊ณ  ํ•˜์ง€ ๋งˆ์„ธ์š”!

2๋‹จ๊ณ„: ํŒ€ ๊ต์œก
STM๊ณผ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•œ ๊ต์œก์„ ์ง„ํ–‰ํ•˜์„ธ์š”. ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๊ด€๋ จ ๊ฐ•์˜๋ฅผ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์—์š”!

3๋‹จ๊ณ„: ์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ”„๋กœ์„ธ์Šค
STM ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋ฆฌ๋ทฐ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋งŒ๋“ค๊ณ , ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ๊ณต์œ ํ•˜์„ธ์š”.

4๋‹จ๊ณ„: ๋ชจ๋‹ˆํ„ฐ๋ง ๊ตฌ์ถ•
ํŠธ๋žœ์žญ์…˜ ์žฌ์‹œ๋„ ํšŸ์ˆ˜, ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜์„ธ์š”.

5๋‹จ๊ณ„: ์ ์ง„์  ํ™•๋Œ€
ํŒŒ์ผ๋Ÿฟ ํ”„๋กœ์ ํŠธ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ๋‹ค๋ฅธ ์˜์—ญ์œผ๋กœ ์ ์ง„์ ์œผ๋กœ ํ™•๋Œ€ํ•˜์„ธ์š”.

; ์‹ค๋ฌด ์˜ˆ์ œ: ๋ชจ๋‹ˆํ„ฐ๋ง์ด ํฌํ•จ๋œ STM ๋ž˜ํผ
(def transaction-stats (atom {:total 0
                               :retries 0
                               :failures 0}))

(defn monitored-dosync [& body]
  (swap! transaction-stats update :total inc)
  (let [start-time (System/nanoTime)
        retry-count (atom 0)]
    (try
      (dosync
        (swap! retry-count inc)
        (when (> @retry-count 1)
          (swap! transaction-stats update :retries inc))
        (apply (first body) (rest body)))
      (catch Exception e
        (swap! transaction-stats update :failures inc)
        (throw e))
      (finally
        (let [duration (/ (- (System/nanoTime) start-time) 1000000.0)]
          (when (> duration 100)
            (println "Warning: Long transaction" duration "ms")))))))

; ์‚ฌ์šฉ ์˜ˆ
(monitored-dosync
  (alter some-ref inc))

; ํ†ต๊ณ„ ํ™•์ธ
@transaction-stats
; => {:total 1000, :retries 23, :failures 2}
๐Ÿ’ก ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ํŒ ๋กœ๊น… ์ „๋žต
ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘/์ข…๋ฃŒ, ์žฌ์‹œ๋„ ๋ฐœ์ƒ์„ ๋กœ๊น…ํ•˜์„ธ์š”. ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜์„ธ์š”.

์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ
์‹ค์ œ ๋ถ€ํ•˜์™€ ์œ ์‚ฌํ•œ ์กฐ๊ฑด์—์„œ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”. ํŠนํžˆ ํ”ผํฌ ์‹œ๊ฐ„๋Œ€๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜์„ธ์š”.

๋กค๋ฐฑ ๊ณ„ํš
๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ๋น ๋ฅด๊ฒŒ ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ณ„ํš์„ ์„ธ์šฐ์„ธ์š”.

๋ฌธ์„œํ™”
STM์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ , ์ฃผ์˜์‚ฌํ•ญ, ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ๋ฌธ์„œํ™”ํ•˜์„ธ์š”.

์ ์ง„์  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
๊ธฐ์กด ๋ฝ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฐ”๊พธ์ง€ ๋ง๊ณ , ์ ์ง„์ ์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜์„ธ์š”.

๐ŸŽจ STM ๋””์ž์ธ ํŒจํ„ด

STM์„ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋””์ž์ธ ํŒจํ„ด์„ ์†Œ๊ฐœํ• ๊ฒŒ์š”! ๐ŸŽฏ

๐Ÿ”น ํŒจํ„ด 1: ์ฝ๊ธฐ-๊ณ„์‚ฐ-์“ฐ๊ธฐ ๋ถ„๋ฆฌ
; โŒ ๋‚˜์œ ์˜ˆ: ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ๋ณต์žกํ•œ ๊ณ„์‚ฐ
(defn bad-update [data-ref]
  (dosync
    (let [current @data-ref
          ; ๋ณต์žกํ•œ ๊ณ„์‚ฐ (ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ!)
          result (expensive-calculation current)]
      (ref-set data-ref result))))

; โœ… ์ข‹์€ ์˜ˆ: ๊ณ„์‚ฐ์€ ๋ฐ–์—์„œ, ํŠธ๋žœ์žญ์…˜์€ ์งง๊ฒŒ
(defn good-update [data-ref]
  (let [current @data-ref
        ; ๋ณต์žกํ•œ ๊ณ„์‚ฐ (ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ!)
        result (expensive-calculation current)]
    (dosync
      ; ๋น ๋ฅธ ๊ฒ€์ฆ ํ›„ ์—…๋ฐ์ดํŠธ
      (when (valid? @data-ref result)
        (ref-set data-ref result)))))
๐Ÿ”น ํŒจํ„ด 2: ์กฐ๊ฑด๋ถ€ ์—…๋ฐ์ดํŠธ
; ์žฌ๊ณ ๊ฐ€ ์ถฉ๋ถ„ํ•  ๋•Œ๋งŒ ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ
(defn conditional-order [inventory-ref order-ref item-id quantity]
  (dosync
    (let [current-stock (get @inventory-ref item-id 0)]
      (if (>= current-stock quantity)
        (do
          (alter inventory-ref update item-id - quantity)
          (alter order-ref conj {:item item-id :qty quantity})
          {:success true})
        {:success false :reason "์žฌ๊ณ  ๋ถ€์กฑ"}))))
๐Ÿ”น ํŒจํ„ด 3: ๋ฐฐ์น˜ ์—…๋ฐ์ดํŠธ
; ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ๊ธฐ
(defn batch-update [data-ref updates]
  (dosync
    (doseq [[key value] updates]
      (alter data-ref assoc key value))))

; ์‚ฌ์šฉ ์˜ˆ
(batch-update my-ref {:a 1 :b 2 :c 3})
; 3๋ฒˆ์˜ ํŠธ๋žœ์žญ์…˜ ๋Œ€์‹  1๋ฒˆ์œผ๋กœ ์ฒ˜๋ฆฌ!
๐Ÿ”น ํŒจํ„ด 4: ๋‚™๊ด€์  ๋ฝ ํŒจํ„ด
; ๋ฒ„์ „ ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•œ ๋‚™๊ด€์  ๋ฝ
(def document (ref {:content "" :version 0}))

(defn update-document [expected-version new-content]
  (dosync
    (let [current @document]
      (if (= (:version current) expected-version)
        (do
          (ref-set document 
                   {:content new-content
                    :version (inc expected-version)})
          {:success true})
        {:success false 
         :reason "๋ฒ„์ „ ์ถฉ๋Œ"
         :current-version (:version current)}))))
๐Ÿ”น ํŒจํ„ด 5: ์ด๋ฒคํŠธ ์†Œ์‹ฑ
; ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ด๋ฒคํŠธ๋กœ ๊ธฐ๋ก
(def state (ref {:balance 1000}))
(def events (ref []))

(defn apply-event [event]
  (dosync
    (case (:type event)
      :deposit (alter state update :balance + (:amount event))
      :withdraw (alter state update :balance - (:amount event)))
    (alter events conj (assoc event :timestamp (System/currentTimeMillis)))))

; ์‚ฌ์šฉ ์˜ˆ
(apply-event {:type :deposit :amount 500})
(apply-event {:type :withdraw :amount 200})

; ์ด๋ฒคํŠธ ํžˆ์Šคํ† ๋ฆฌ๋กœ ์ƒํƒœ ์žฌ๊ตฌ์„ฑ ๊ฐ€๋Šฅ!

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌ: STM์ด ๊ฐ€์ ธ์˜จ ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ๋ณ€ํ™”

์—ฌ๊ธฐ๊นŒ์ง€ Clojure์˜ STM์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ์•Œ์•„๋ดค์–ด์š”! ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ฃ ? ๐Ÿ˜Š

STM์€ ๋‹จ์ˆœํžˆ ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ, ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•œ ์‚ฌ๊ณ ๋ฐฉ์‹์˜ ์ „ํ™˜์„ ๊ฐ€์ ธ์™”์–ด์š”. "์–ด๋–ป๊ฒŒ ๋ฝ์„ ๊ด€๋ฆฌํ• ๊นŒ?"์—์„œ "์–ด๋–ป๊ฒŒ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์กฐ์œจํ• ๊นŒ?"๋กœ ์งˆ๋ฌธ์ด ๋ฐ”๋€ ๊ฑฐ์ฃ .

์ „ํ†ต์ ์ธ ๋ฐฉ์‹์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฝ์˜ ์ˆœ์„œ, ๋ฐ๋“œ๋ฝ ํšŒํ”ผ, ๊ฒฝ์Ÿ ์กฐ๊ฑด ๋“ฑ์„ ๋ชจ๋‘ ์‹ ๊ฒฝ ์จ์•ผ ํ–ˆ์–ด์š”. ํ•˜์ง€๋งŒ STM์—์„œ๋Š”? ๊ทธ๋ƒฅ dosync ๋ธ”๋ก ์•ˆ์— ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑํ•˜๋ฉด ๋์ด์—์š”. ๋‚˜๋จธ์ง€๋Š” ๋Ÿฐํƒ€์ž„์ด ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ์ฃ ! ๐ŸŽ‰

๐ŸŒŸ STM์˜ ํ•ต์‹ฌ ๊ฐ€์น˜ 1. ๋‹จ์ˆœ์„ฑ
๋ณต์žกํ•œ ๋ฝ ๊ด€๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์–ด์š”.

2. ์•ˆ์ „์„ฑ
๋ฐ๋“œ๋ฝ, ๋ ˆ์ด์Šค ์ปจ๋””์…˜ ๊ฐ™์€ ๊ณ ์งˆ์ ์ธ ๋ฌธ์ œ๋“ค์ด ์›์ฒœ์ ์œผ๋กœ ์ฐจ๋‹จ๋ผ์š”.

3. ์ปดํฌ์ €๋นŒ๋ฆฌํ‹ฐ
์ž‘์€ ํŠธ๋žœ์žญ์…˜๋“ค์„ ์กฐํ•ฉํ•ด์„œ ํฐ ํŠธ๋žœ์žญ์…˜์„ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›Œ์š”.

4. ์œ ์ง€๋ณด์ˆ˜์„ฑ
์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›Œ์„œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํŽธํ•ด์š”.

5. ํ™•์žฅ์„ฑ
๋ฝ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์—†์–ด์„œ ๋” ๋งŽ์€ ๋™์‹œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.

๋ฌผ๋ก  STM์ด ๋ชจ๋“  ๋ฌธ์ œ์˜ ํ•ด๋‹ต์€ ์•„๋‹ˆ์—์š”. ๋ถ„์‚ฐ ์‹œ์Šคํ…œ, ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ, I/O ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋“ฑ์—์„œ๋Š” ๋‹ค๋ฅธ ์ ‘๊ทผ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ์ ์ ˆํ•œ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, STM์€ ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ’ช

ํŠนํžˆ ๊ธˆ์œต, ๊ฒŒ์ž„, ํ˜‘์—… ๋„๊ตฌ ๊ฐ™์ด ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋ถ„์•ผ์—์„œ STM์˜ ์ง„๊ฐ€๊ฐ€ ๋ฐœํœ˜๋ผ์š”. ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ๋„ ๊ฑฐ๋ž˜ ์ฒ˜๋ฆฌ, ํฌ์ธํŠธ ๊ด€๋ฆฌ, ์žฌ๊ณ  ๊ด€๋ฆฌ ๋“ฑ์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”!

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๋ถˆ๋ณ€์„ฑ, ๊ทธ๋ฆฌ๊ณ  STM. ์ด ์„ธ ๊ฐ€์ง€๊ฐ€ ๋งŒ๋‚˜๋ฉด ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ์ •๋ง ์šฐ์•„ํ•ด์ ธ์š”. ๋งˆ์น˜ ๋ณต์žกํ•œ ์˜ค์ผ€์ŠคํŠธ๋ผ๋ฅผ ์ง€ํœ˜ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์กฐํ™”๋กญ๊ฒŒ ํ˜‘๋ ฅํ•˜๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ์ฃ . ๐ŸŽผ

๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‚˜์•„๊ฐ€๊ธฐ ์ด ๊ธ€์„ ์ฝ์€ ์—ฌ๋Ÿฌ๋ถ„์€ ์ด์ œ STM์˜ ๊ธฐ๋ณธ๋ถ€ํ„ฐ ๊ณ ๊ธ‰ ๊ฐœ๋…๊นŒ์ง€ ๋ชจ๋‘ ์ดํ•ดํ•˜์…จ์„ ๊ฑฐ์˜ˆ์š”. ๋‹ค์Œ ๋‹จ๊ณ„๋Š”?

1. ์ง์ ‘ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ
์ด๋ก ๋งŒ ์•„๋Š” ๊ฒƒ๊ณผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฑด ์™„์ „ํžˆ ๋‹ฌ๋ผ์š”. ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด์„ธ์š”!

2. ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๋ถ„์„
GitHub์—์„œ Clojure ํ”„๋กœ์ ํŠธ๋ฅผ ์ฐพ์•„๋ณด๊ณ , STM์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด์„ธ์š”.

3. ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฐธ์—ฌ
ClojureVerse, Reddit์˜ r/Clojure ๋“ฑ์—์„œ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ์†Œํ†ตํ•˜์„ธ์š”.

4. ์‹ค์ „ ํ”„๋กœ์ ํŠธ ๋„์ „
์‹ค์ œ ๋ฌธ์ œ๋ฅผ STM์œผ๋กœ ํ•ด๊ฒฐํ•ด๋ณด์„ธ์š”. ์‹คํŒจํ•ด๋„ ๊ดœ์ฐฎ์•„์š”. ๊ทธ๊ฒŒ ์ตœ๊ณ ์˜ ํ•™์Šต์ด์—์š”!

5. ์ง€์‹ ๊ณต์œ 
๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ธ”๋กœ๊ทธ์— ์ •๋ฆฌํ•˜๊ฑฐ๋‚˜, ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๊ณต์œ ํ•ด๋ณด์„ธ์š”!

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์–ด๋ ค์›Œ์š”. ํ•˜์ง€๋งŒ STM ๊ฐ™์€ ๋„๊ตฌ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ์‰ฌ์›Œ์งˆ ์ˆ˜ ์žˆ์–ด์š”. ์ค‘์š”ํ•œ ๊ฑด ์˜ฌ๋ฐ”๋ฅธ ๋„๊ตฌ๋ฅผ ์˜ฌ๋ฐ”๋ฅธ ์ƒํ™ฉ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์—์š”. ๐ŸŽฏ

์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— STM์ด ํ•„์š”ํ•œ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์„ธ์š”. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ์กฐ์œจํ•ด์•ผ ํ•˜๋Š” ๋ณต์žกํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋ฉด, Clojure์™€ STM์ด ํ›Œ๋ฅญํ•œ ํ•ด๊ฒฐ์ฑ…์ด ๋  ์ˆ˜ ์žˆ์–ด์š”!

์ด ๊ธ€์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์—ฌ์ •์— ๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ผ์š”. ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์„ธ๊ณ„๋Š” ๋„“๊ณ  ๊นŠ์–ด์š”. STM์€ ๊ทธ ์ค‘ ํ•˜๋‚˜์˜ ์•„๋ฆ„๋‹ค์šด ์กฐ๊ฐ์ผ ๋ฟ์ด์—์š”. ๊ณ„์† ํƒํ—˜ํ•˜๊ณ , ๋ฐฐ์šฐ๊ณ , ์„ฑ์žฅํ•˜์„ธ์š”! ๐ŸŒฑ

Happy coding! ๊ทธ๋ฆฌ๊ณ  ๋™์‹œ์„ฑ ๋ฒ„๊ทธ ์—†๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”! ๐Ÿ˜„โœจ

๐Ÿ“š ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์…จ๋‚˜์š”?

๋” ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์‹๊ณผ ์‹ค์ „ ๋…ธํ•˜์šฐ๊ฐ€ ํ•„์š”ํ•˜์‹œ๋‹ค๋ฉด,
์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์˜ '์ง€์‹์ธ์˜ ์ˆฒ'์—์„œ
๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ ๊ด€๋ จ ์ปจํ…์ธ ๋ฅผ ๋งŒ๋‚˜๋ณด์„ธ์š”! ๐ŸŒŸ

์—ฌ๋Ÿฌ๋ถ„์˜ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ณ , ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜์„ธ์š”! ๐Ÿš€

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.