์•ž์—์„œ๋Š” Swift concurrency๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” Swift concurrency๋ฅผ ์ฑ„ํƒํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•˜๋Š”์ , ๊ทธ๋ฆฌ๊ณ  Actor๋ฅผ ํ†ตํ•œ Synchronization์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

Adoption of Swift Concurrency

์ด๋ฒˆ์—๋Š” Swift Concurrency๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

Performance

์•ž์—์„œ Concurrency๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ถ”๊ฐ€ memory๊ณผ ๊ด€๋ จ๋œ cost์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. ์ด๋Ÿฌํ•œ ์ ์€ ์—ฌ์ „ํžˆ ์ ์šฉ๋˜๋ฉฐ, Concurrency๋ฅผ ๋„์ž…ํ•˜์—ฌ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๋น„์šฉ์ด ์ฝ”๋“œ์˜ ๊ด€๋ฆฌ ๋น„์šฉ์„ ๋„˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•œ๋‹ค.

async let isThumbnailView = userDefaults.bool(forKey: "ViewType")
 
if await isThumbnailView {
 
} else {
 
}

์œ„์™€ ๊ฐ™์ด userDefaults์—์„œ ๋‹จ์ˆœํžˆ ๊ฐ’์„ ์ผ์–ด์˜ค๋Š”๋ฐ ์žˆ์–ด์„œ ๊ตณ์ด asyncํ•˜๊ฒŒ task๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฒ˜๋ฆฌํ•  ํ•„์š”๋Š” ์—†๋‹ค. task๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋น„์šฉ์ด, task๋ฅผ ๋งŒ๋“œ๋Š” ๋น„์šฉ๋ณด๋‹ค ํฌ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— apple์—์„œ๋Š” Instruments system์„ ํ†ตํ•ด Swift concurrency๋ฅผ ์ฑ„ํƒํ–ˆ์„ ๋•Œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์„ฑ๋Šฅ ์ง€ํ‘œ๋“ค์„ ํ™•์ธํ•ด๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

Notion of Atomicity around await

await์— ๊ฑธ์ณ lock์„ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค.

Swift๋Š” await ์ด์ „์— ์‹คํ–‰๋˜์—ˆ๋˜ thread์™€ ์ดํ›„์— ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ์˜ thread๊ฐ€ ๊ฐ™์€ ๊ฒƒ์„ ๋ณด์žฅํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค. ์ด๋Š” ์•ž์—์„œ await ๊ทผ๋ฐฉ์—์„œ ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ๊ทผ๊ฐ„์œผ๋กœ ํ•œ๋‹ค. await๋Š” ์ฝ”๋“œ์—์„œ ์ž‘์—…์ด ์ž๋ฐœ์ ์œผ๋กœ ์ทจ์†Œ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ž‘์—…์˜ ์›์ž์„ฑ์ด ๊นจ์กŒ์Œ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋‚˜ํƒ€๋‚ด๋Š” ์ง€์ ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ๊ทธ ๊ธ‰๋ฐฉ์—์„œ lock์„ ๊ฑธ๋ฉด ์•ˆ๋œ๋‹ค. ๋‹ค์‹œ ํ•ด๋‹น thread๋กœ ๋Œ์•„์˜จ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

thread์— ํŠนํ™”๋œ ๋ฐ์ดํ„ฐ๋Š” await์— ๊ฑธ์ณ ๋ณด์กด๋˜์ง€ ์•Š๋Š”๋‹ค.

์ด ์—ญ์‹œ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. await ๋‹ค์Œ ๋™์ž‘ํ•˜๋Š” thread ๋ณด์žฅ์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ ‘์„ฑ์„ ๊ฐ€์ •ํ•˜๊ณ  ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” ์žฌ๊ฒ€ํ† ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

Runtime contract๋ฅผ ๋ณด์กดํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, thread๊ฐ€ ๊ณ„์†ํ•ด์„œ ์•ž์œผ๋กœ ์ „์ง„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

thread์˜ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ณ , ๊ฐ task์—์„œ continuation์„ ํ†ตํ•ด ๋™์ž‘์„ ๋‚˜์•„๊ฐ€๊ฒŒ ํ•˜๋Š” ๋งŒํผ, ์ด ๊ด€๋ฆฌ๋Š” ์ค‘์š”ํ•˜๋‹ค. ์ฆ‰, Cooperativeํ•œ thread pool์„ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

|โœ…
Safe primitives|โš ๏ธ
Caution required|๐Ÿ›‘
unsafe primitives| |:----------------:โ€”|:------------------:----|:------------------:---| |await,
Actors,
Task groups|๋™๊ธฐ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋Š”
os_unfair_lock,
NSLock|DispatchSemephore,
pthread_cond,
NSCondition,
pthread_rw_loc,
โ€ฆ| |Compiler ๊ฐ•์ œ|Compiler ๋ณด์กฐ ์—†์Œ|Compiler ๋ณด์กฐ ์—†์Œ| ||์ž˜ ์•Œ๋ ค์ง„ critical section ์ฃผ๋ณ€์—์„œ ๋™๊ธฐ ์ฝ”๋“œ๋กœ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์•ˆ์ „, ํ•˜์ง€๋งŒ ์œ„ํ—˜์„ฑ ์žˆ์Œ|์ด ๊ฒฝ์šฐ๋Š” Swift runtime์— dependency ์ •๋ณด๋ฅผ ์ˆจ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค.|

Task boundary๋ฅผ ๋„˜์–ด awaitํ•˜๋Š” ๋ถˆ์•ˆ์ „ํ•œ ์›์‹œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ๋ผ. ํŠนํžˆ semaphore๋‚˜ ๋ถˆ์•ˆ์ „ํ•œ ์›์‹œํƒ€์ž…์„ ํ†ตํ•ด ๊ตฌ์กฐํ™”๋˜์ง€ ์•Š์€ task๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ๋ผ.

func updateDatabase(_ asyncUpdateDatabase: @Sendable @escaping () async -> Void) {
    let semaphore = DispatchSemaphore(value: 0)
 
    Task {
        await asyncUpdateDatabase()
        semaphore.signal()
    }
 
    semaphore.wait()
}

๋”ฑ deadlock ๋ฐœ์ƒํ•˜๊ธฐ ์ข‹์€ ์ฝ”๋“œ๋‹ค. Task๊ฐ€ ๋“ค์–ด๊ฐ„ ํŠน์ • thread์—์„œ unblockํ•˜๊ธฐ ์ „๊นŒ์ง€ ํŠน์ • thread๊ฐ€ ๋ฌดํ•œ ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด runtime contract๋ฅผ ์œ„๋ฐ˜ํ•œ ๊ฒƒ์ด๋‹ค. ๋‹ค์Œ ์ž‘์—…์„ ์ด์–ด๋‚˜๊ฐˆ ์ˆ˜ ์—†๋„๋ก ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Synchronization via Actor

์ด์ „์— ์•Œ์•„๋ณธ Actor๋Š” concurrentํ•œ ์ ‘๊ทผ์— ๋Œ€ํ•ด mutable state๋ฅผ ์–ด๋–ป๊ฒŒ actor๊ฐ€ ๋ฐฉ์–ดํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๋‹ค. Actor๊ฐ€ ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ๋ณด์žฅํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด๋ณด์ž.

Mutual exclusion

์•ž์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ databaseQueue์— ๋„˜๊ฒผ๋˜ ๋™์ž‘์„ ์ƒ๊ฐํ•ด๋ณด์ž.

databaseQueue.sync { updateDatabase(articles, for: feed) } // 1๏ธโƒฃ
databaseQueue.async { /* background work */ } // 2๏ธโƒฃ

|Comparison|1๏ธโƒฃ
Locks,
Serial Queue sync { โ€ฆ}|2๏ธโƒฃ
Serial Queue async (โ€ฆ }|3๏ธโƒฃ
Actors using cooperative pool| |:--------:|:----------------------------------:----|:------------------------------:----|:--------------------------------:----| |No contention (the queue is not already running)|โœ… Reuse thread|โš ๏ธ Request new thread|โœ… Reuse thread| |Under contention (the queue is already running)|๐Ÿ›‘ Blocking|โœ… Non-blocking|โœ… Non-blocking|

๋จผ์ €, Queue๊ฐ€ ๋™์ž‘์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด, ์ฆ‰ ๊ฒฝ์Ÿ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ ์—†๋‹ค. ํ˜„์žฌ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” Thread๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Serial Queue๊ฐ€ ์ด๋ฏธ ๋™์ž‘์ค‘์ด๋‹ค. ์ฆ‰, ๊ฒฝ์Ÿ ์ƒํƒœ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ํ˜ธ์ถœํ•˜๋Š” thread(databaseQueue.sync๋ฅผ ํ˜ธ์ถœํ–ˆ๋˜ thread)๋Š” block๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด blocking ๋™์ž‘์ด ๋ฐ”๋กœ thread explosion์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ํ–‰๋™์ด๋‹ค.

blocking์˜ ๋ฌธ์ œ ๋•Œ๋ฌธ์—, ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” dispatch async๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. dispatch async์˜ ์ฃผ์š” ์ด์ ์€, non-blocking์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฝ์Ÿ ์ƒํƒœ์— ๋†“์ด๋”๋ผ๋„ thread explosion์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. (๋ฐ”๋กœ thread๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ์ž‘์—…๋งŒ ๋’ค์— ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ) dispatch serial queue async์˜ ๋‹จ์ ์œผ๋กœ๋Š” ๊ฒฝ์Ÿ์ด ์—†๋Š” ๊ฒฝ์šฐ ํ˜ธ์ถœํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณ„์† ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ Dispatch๊ฐ€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ ์Šค๋ ˆ๋“œ๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ dispatch async์˜ ๋นˆ๋ฒˆํ•œ ์‚ฌ์šฉ์€, ๊ณผ๋„ํ•œ thread wakeup๊ณผ context switching์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•„์š”์„ฑ์—์„œ Actor๊ฐ€ ๋‚˜์™”๋‹ค. Swift์˜ Actor๋Š” ํšจ์œจ์ ์ธ ์Šค์ผ€์ค„๋ง์„ ์œ„ํ•ด Cooperative thread pool์„ ํ™œ์šฉํ•˜์—ฌ ๋‘ ์„ธ๊ณ„์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•œ๋‹ค. ์‹คํ–‰ ์ค‘์ด ์•„๋‹Œ Actor์—์„œ method๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ํ˜ธ์ถœํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด ํ˜ธ์ถœํ•œ thread๋Š” ๋™์ž‘์„ suspendํ•˜๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ๊ฐ€์ ธ์™€์„œ ์‹คํ–‰ํ•œ๋‹ค.

Actor hopping

actor๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด์ž.

news feed๋ฅผ ๋งŒ๋“œ๋Š” ์•ฑ์—์„œ, database์™€ networking์„ ์ฒ˜๋ฆฌํ–ˆ๋˜ subsystem์„ ์‚ดํŽด๋ณด์ž.

Swift concurrency๋กœ ๋„˜์–ด์˜ค๋ฉด, GCD์—์„œ ์žˆ๋˜ serial queue๋Š” Database Actor๋กœ ๋ฐ”๋€๋‹ค. ๊ทธ๋ฆฌ๊ณ  Concurrent Queue๋Š” ๊ฐ๊ฐ์— ํ•ด๋‹น๋˜๋Š” Actor๋กœ ๋ฐ”๋€๋‹ค.

์ด ๋ชจ๋“  Actor๋“ค์€ Cooperative thread pool์—์„œ ๋™์ž‘ํ•œ๋‹ค. feed actor๋Š” article ์ €์žฅ, ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ๋ชฉ์ ๋“ค์„ ์œ„ํ•ด database actor์™€ ์ƒํ˜ธ์ž‘์šฉํ•œ๋‹ค. ์ด๊ฑธ actor hopping process๋ผ ํ•œ๋‹ค. ์ด hopping process๊ฐ€ ์–ด๋–ป๊ฒŒ ์ผ์–ด๋‚˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

sports feed๋ฅผ ์œ„ํ•œ actor๊ฐ€ cooperative thread์œ„์—์„œ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ์ด feed๋Š” ๋ช‡ article์„ database์— ์ €์žฅํ•˜๊ณ  ์‹ถ๋‹ค. ๊ทธ๋ฆฌ๊ณ  database actor๋Š” ์•„์ง ์‚ฌ์šฉ๋œ ์ ์ด ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์ฆ‰, untended case์ด๋‹ค.

Thread๋Š” ์ง์ ‘์ ์œผ๋กœ sports feed actor์—์„œ database actor๋กœ hoppingํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•ด์•ผ ํ•˜๋Š” ์ ์€ ๋‘๊ฐ€์ง€์ด๋‹ค.

  1. hopping actor์‹œ์— thread๋Š” block๋˜์ง€ ์•Š์•˜๋‹ค.
  2. hopping์„ ํ•˜๋Š”๋ฐ ์žˆ์–ด ๋‹ค๋ฅธ thread๊ฐ€ ํ•„์š”์—†๋‹ค.

runtime์—์„œ ์ง์ ‘์ ์œผ๋กœ sport feed actor๋ฅผ ์œ„ํ•ด work item์„ suspendํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  database actor๋ฅผ ์œ„ํ•ด ์ƒˆ๋กœ์šด work item์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.

database actor๊ฐ€ ์–ด๋Š์ •๋„ ์‹คํ–‰๋˜์—ˆ์ง€๋งŒ, ์ฒซ๋ฒˆ์งธ work item์˜ ์‹คํ–‰์ด ๋ชจ๋‘ ๋๋‚˜์ง€๋Š” ์•Š์•˜๋‹ค๊ณ  ํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ์ด์ˆœ๊ฐ„์— weather feed actor๊ฐ€ ๋ช‡ article์„ database์— ์ €์žฅํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ณด์ž.

์ด๋Ÿฐ ๊ฒฝ์šฐ, database actor๋ฅผ ์œ„ํ•ด ์ƒˆ๋กœ์šด work item์ด ์ƒ์„ฑ๋œ๋‹ค. actor๋Š” ์ƒํ˜ธ๋ฐฐ์ œ๋Š” ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ธฐ๊ปํ•ด์•ผ ํ•˜๋‚˜์˜ work item๋งŒ ์ฃผ์–ด์ง„ ์‹œ๊ฐ„์— ํ™œ์„ฑํ™” ๋œ๋‹ค.

actor ์—ญ์‹œ non-blocking์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ weather feed์˜ ๊ฒฝ์šฐ suspend๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  thread๋Š” ์ด์ œ freed ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์–ด๋Š์ •๋„ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„์—, ์ตœ์ดˆ database ์š”์ฒญ(D1)์ด ์™„๋ฃŒ๋˜์—ˆ๊ณ , database actor์— ์žˆ๋˜ ํ™œ์„ฑํ™”๋œ work item์€ ์ œ๊ฑฐ๋œ๋‹ค.

runtime์€ ๋‹ค์Œ์œผ๋กœ ์ง€์—ฐ๋˜์–ด ์žˆ๋˜ work item์ธ D2๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

๋˜๋Š” feed actors ๋“ฑ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ณจ๋ผ ์žฌ๊ฐœํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ํ˜น์€ ๋‹ค๋ฅธ work๋ฅผ ๊ฐ€์ ธ์™€ freed ๋œ thread์—์„œ ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Reentrancy and prioritization

  1. ๋น„๋™๊ธฐ ์ž‘์—…์ด ๋งŽ๊ฑฐ๋‚˜
  2. contention์ด ๋งŽ์ด ์ด๋ฃจ์–ด์ง€๊ณ  ์žˆ๊ฑฐ๋‚˜

์œ„์˜ ๋‘๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ system์€ ์–ด๋–ค work๊ฐ€ ๋” ์ค‘์š”ํ•œ์ง€์— ๋Œ€ํ•ด์„œ ํŒ๋‹จํ•ด์•ผ ํ•œ๋‹ค. ์ด์ƒ์ ์œผ๋กœ user interaction๊ณผ ๊ฐ™์ด ์ตœ์šฐ์„ ์ˆœ์œ„์˜ work๊ฐ€ backup๊ณผ ๊ฐ™์€ work์— ๋น„ํ•ด ์šฐ์„ ์ ์œผ๋กœ ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

Actor๋Š” Reentrancy(์žฌ์ง„์ž…)์ด๋ผ๋Š” ๊ฐœ๋… ๋•Œ๋ฌธ์— ์‹œ์Šคํ…œ์ด work์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ž˜ ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค. ๊ทธ ์ „์—, ์™œ reentrancy๊ฐ€ ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ์ง€ ๋ถ€ํ„ฐ ์•Œ์•„๋ณด์ž.

Serial dispatch queues

๋‹น์žฅ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ž‘์—…์„ database์—๊ฒŒ ์š”์ฒญํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ์œผ๋กœ๋Š” iCloud์— backup์„ ํ•˜๋Š” ์šฐ์„ ์ˆœ์œ„์—์„œ ์ƒ๋Œ€์ ์œผ๋กœ ๋ฐ€๋ฆฌ๋Š” ์ž‘์—…์„ ์š”์ฒญํ•˜์ž. ๊ทธ๋Ÿฌ๋ฉด ์š”์ฒญ์„ ํ•œ ์ˆœ์„œ๋Œ€๋กœ serial queue์— ์œ„์™€ ๊ฐ™์ด ์Œ“์ด๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

DispatchQueue๋Š” FIFO ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋“ค์–ด๊ฐ„ ์ˆœ์„œ๋Œ€๋กœ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๋ง์€ ๊ณง item A๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋‚œ ํ›„, ๋‚ฎ์€ ์šฐ์„  ์ˆ˜์œ„๋ฅผ ๊ฐ€์ง€๋Š” 5๊ฐœ์˜ item์ด 6๋ฒˆ์จฐ ์œ„์น˜ํ•œ ๋†’์€ ์šฐ์„  ์ˆœ์œ„ item๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•จ์„ ๋œปํ•œ๋‹ค. ์ด๋ฅผ ์šฐ์„  ์ˆœ์œ„ ์—ญ์ „์ด๋ผ ํ•œ๋‹ค.

Serial Queue๋Š” ๋†’์€ ์šฐ์„  ์ˆœ์œ„ ์ž‘์—…๋ณด๋‹ค ์•ž์— ์žˆ๋Š” Queue์˜ ๋ชจ๋“  ์ž‘์—…์˜ ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋†’์ž„์œผ๋กœ์จ ์šฐ์„  ์ˆœ์œ„ ์—ญ์ „์„ ๋ฐฉ์ง€ํ•œ๋‹ค. ์ฆ‰, ์ด ๋ง์€ queue์•ˆ์— ์žˆ๋Š” work๋“ค์ด ๋” ๋นจ๋ฆฌ ์™„๋ฃŒ๋จ์„ ๋งํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ 1์—์„œ 5๊นŒ์ง€ ์›์†Œ๊ฐ€ B๋ณด๋‹ค ๋จผ์ € ์™„๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์—์„œ main issue๋ฅผ ํ•ด๊ฒฐํ•˜์ง€๋Š” ๋ชปํ•œ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋นก๋นกํ•œ FIFO ๊ทœ์ •์„ ๋ฒ„๋ ค์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์ ์—์„œ actor reentrancy๊ฐ€ ๊ณ ์•ˆ๋˜์—ˆ๋‹ค.

Actor reentrancy

database actor๊ฐ€ thread์œ„์—์„œ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋‹ค ์ƒ๊ฐํ•ด๋ณด์ž.

database actor๋Š” suspend ๋˜์—ˆ๊ณ , ๊ทธ ์ž๋ฆฌ๋ฅผ sports feed actor๊ฐ€ ์ฐจ์ง€ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

sports feed actor๋Š” ์–ผ๋งˆ ์ง€๋‚˜์ง€ ์•Š์•„ ๋™์ž‘์„ ์™„๋ฃŒํ–ˆ๊ณ , database actor์—๊ฒŒ article์„ ์ €์žฅํ•ด๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ–ˆ๋‹ค. database actor๋Š” uncontended(์‹ค์ œ ๋™์ž‘ํ•˜๊ณ  ์žˆ์ง€ ์•Š์Œ, ๊ฒฝ์Ÿ X) ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์—, pendingํ•œ ์ž‘์—…(D1)์ด ์žˆ์Œ์—๋„ thread๋Š” database actor๋ฅผ hoppingํ•  ์ˆ˜ ์žˆ๋‹ค.

save ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ƒˆ๋กœ์šด work item์ด database actor๋ฅผ ์œ„ํ•ด ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ด๊ฑธ actor reentrancy๋ผ ํ•œ๋‹ค.

actor์— ์˜ฌ๋ ค์ง„ ์ƒˆ๋กœ์šด work item์ด ํ•˜๋‚˜ ํ˜น์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ด์ „ ์ž‘์—…์ด suspend๋œ ์ƒํƒœ์—์„œ ์•ž์œผ๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋™์ž‘์„ actor reentrancy๋ผ ํ•œ๋‹ค.

actor๋Š” ์—ฌ์ „ํžˆ ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ๋งŒ์กฑํ•œ๋‹ค. ๊ธฐ๊ปํ•ด์•ผ ํ•˜๋‚˜์˜ item๋งŒ์ด ํ•ด๋‹น ์‹œ๊ฐ„์— ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์–ด๋Š์ •๋„ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„์—, D2๋Š” ์‹คํ–‰์„ ๋งˆ์นœ๋‹ค. D2๊ฐ€ D1๋ณด๋‹ค ๋‚˜์ค‘์— ์ƒ์„ฑ๋˜์—ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋จผ์ € ์ž‘์—…์„ ๋๋‚˜์ณค๋‹ค๋Š” ๊ฒƒ์„ ์ฃผ๋ชฉํ•˜์ž. ๊ทธ๋Ÿฌ๋ฏ€๋กœ, actor reentrancy๋ฅผ ์ง€์›ํ•œ๋‹ค๋Š” ๋ง์€ actor๊ฐ€ ์—„๊ฒฉํ•œ FIFO ์ˆœ์„œ๋ฅผ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” ๋ฐฉ์‹์œผ๋กœ item์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Œ์„ ๋œปํ•œ๋‹ค.

Actor reprioritization

์ด๋Ÿฐ actor reentrancy๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฑธ๋ฆฐ ์ž‘์—…์ด ์–ด๋–ป๊ฒŒ ์ด๋ฃจ์–ด์ง€๋Š” ์ง€ ํ™•์ธํ•ด๋ณด์ž.

๋จผ์ €, ๊ฐ€์žฅ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ A item์ด ์‹คํ–‰๋  ๊ฒƒ์ด๋‹ค.

actor reentrancy์— ๋”ฐ๋ผ runtime์€ ์ตœ์šฐ์„  ์ˆœ์œ„ work item์„ queue์˜ ์ตœ์ƒ๋‹จ์œผ๋กœ ์˜ฎ๊ธด๋‹ค.

์ด๋Š” ์šฐ์„  ์ˆœ์œ„ ์—ญ์ „ ๋ฌธ์ œ๋ฅผ ์ง์ ‘ ํ•ด๊ฒฐํ•˜์—ฌ ๋ณด๋‹ค ํšจ๊ณผ์ ์ธ ์Šค์ผ€์ค„๋ง๊ณผ ๋ฆฌ์†Œ์Šค ํ™œ์šฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

Main actor

๋งˆ์ง€๋ง‰์œผ๋กœ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ actor๊ฐ€ ์žˆ๋‹ค. main actor๋Š” ์‹œ์Šคํ…œ์˜ ๊ธฐ์กด ๊ฐœ๋…์ธ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ถ”์ƒํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์†Œ ๋‹ค๋ฅด๋‹ค.

๋‹ค์‹œ actor๋ฅผ ์‚ฌ์šฉํ•œ news feed๋ฅผ ๋ฐ›์•„์˜ค๋Š” app์„ ๋– ์˜ฌ๋ ค๋ณด์ž. user interface๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ, ์šฐ๋ฆฌ๋Š” main actor๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค. cooperative pool์•ˆ์— ์žˆ๋Š” thread๋กœ๋ถ€ํ„ฐ main thread๋Š” ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์ž‘์—…์€ context switching์„ ์š”ํ•œ๋‹ค.

// on database actor
func loadArticle(with id: ID) async throws -> Article { /* ... */ }
 
@MainActor func updateUI(for article: Article) async { /* ... */ }
 
@MainActor func updateArticles(for ids: [ID]) async throws {
    for id in ids {
        let article = try await database.loadArticle(with: id) // โœ… context switching
        await updateUI(for: article)
    }
}

database๋กœ๋ถ€ํ„ฐ article์„ ๋กœ๋“œํ•˜๊ณ  ๊ฐ ๊ธฐ์‚ฌ์˜ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณด์ž. ๊ฐ๊ฐ์˜ loop์—์„œ ์ ์–ด๋„ ๋‘๋ฒˆ์˜ context switching์ด ์ผ์–ด๋‚œ๋‹ค.

  1. main actor์—์„œ database actor๋กœ
  2. database actor์—์„œ main actor๋กœ

๋ฃจํ”„ ๋ฐ˜๋ณต ํšŸ์ˆ˜๊ฐ€ ์ ๊ณ  ๊ฐ ๋ฐ˜๋ณต์—์„œ ์ƒ๋‹นํ•œ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜๊ณ  ์žˆ๋‹ค๋ฉด ๊ดœ์ฐฎ์„ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹คํ–‰์ด main actor๋ฅผ ์ž์ฃผ ์˜ค๊ฐ€๋Š” ๊ฒฝ์šฐ thread ์ „ํ™˜์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ˆ„์ ๋˜๊ธฐ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์ด ์ปจํ…์ŠคํŠธ ์ „ํ™˜์— ๋งŽ์€ ์‹œ๊ฐ„์„ ์†Œ๋น„ํ•œ๋‹ค๋ฉด, main actor์— ๋Œ€ํ•œ ์ž‘์—…์ด ์ผ๊ด„ ์ฒ˜๋ฆฌ๋˜๋„๋ก ์ฝ”๋“œ ๊ตฌ์„ฑ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

cooperative pool์—์„œ actor๋“ค ๊ฐ„์˜ hopping์€ ๋น ๋ฅด์ง€๋งŒ, ์•ฑ์„ ์ž‘์„ฑํ•  ๋•Œ๋Š” ์—ฌ์ „ํžˆ main actor์™€์˜ hopping๋ฅผ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•œ๋‹ค.

๋งˆ์น˜๋ฉฐ

Swift concurrency๋Š” ์„ฑ๋Šฅ, ๊ฐ€๋…์„ฑ, ์•ˆ์ •์„ฑ์„ ๋ชจ๋‘ ๊ณ ๋ คํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

  • await ๊ทผ์ฒ˜์—์„œ๋Š” suspension์ด ์ผ์–ด๋‚œ๋‹ค.
  • Thread์˜ blocking์ด ์—†์œผ๋ฉฐ, asyncํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ heap์— ๋‹ค์Œ ์ฒ˜๋ฆฌ ๊ณผ์ •์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • ๊ทธ๋ ‡๊ธฐ์— thread์˜ ๋™์ž‘์ด ๋Œ์•„์˜ฌ ๋•Œ ๊ฐ™์€ thread๋ผ๋Š” ๋ณด์žฅ์ด ์—†๋‹ค.
  • actor๋Š” ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ๋ณด์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์œ ์—ฐํ•œ FIFO ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ ธ, ์šฐ์„ ์ˆœ์œ„ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • main actor๋Š” main thread์™€ ๊ด€๋ จ์žˆ๋‹ค.

Reference