Potato
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์žก๋‹ˆ๋‹ค?๐Ÿฅ” ^___^ ๐Ÿ˜บ github ๋ฐ”๋กœ๊ฐ€๊ธฐ ๐Ÿ‘‰๐Ÿป

Swift/Swift Documents

[Swift] ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ (18) - Concurrency (๋™์‹œ์„ฑ, actor, async, await, ๋น„๋™๊ธฐ, ๋ณ‘๋ ฌ์ฝ”๋“œ)

๊ฐ์ž ๐Ÿฅ” 2022. 3. 8. 23:54
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์ž์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ WWDC21 ์—์„œ ๋“ฑ์žฅํ•œ ๋™์‹œ์„ฑ์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ–ˆ์–ด์š”.. ๋„˜ ์–ด๋ ต๋”๊ตฐ์š” ใ… ใ…  ๊ทธ๋ž˜์„œ ์กฐ๊ธˆ ๋” ์ฐธ๊ณ ํ•˜๊ณ  ์ดํ•ด๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™์•„์š”.. ํ‘ํ‘.. ๊ทธ๋ž˜์„œ ๊ณต์‹๋ฌธ์„œ ๋งจ ๋งˆ์ง€๋ง‰์— ์ฐธ๊ณ ํ•ด์„œ ๋” ๊ณต๋ถ€ํ•ด๋ณผ ์ž๋ฃŒ๋ฅผ ์ฒจ๋ถ€ํ•ด๋‘์—ˆ์–ด์š”. ๋ชจ๋‘ ๊ฐ€์„œ ์ฝ์–ด๋ณด๊ณ  ์ œ๋Œ€๋กœ ๋œ ์ดํ•ด๋ฅผ ํ•ด๋ด…์‹œ๋‹ค ใ… ใ…  ์•„์ง ๊ฐˆ๊ธธ์ด ๋ฉ€๊ตฐ์š”..

Swift documents chap.18 Concurrency ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

 

Concurrency — The Swift Programming Language (Swift 5.6)

Concurrency Swift has built-in support for writing asynchronous and parallel code in a structured way. Asynchronous code can be suspended and resumed later, although only one piece of the program executes at a time. Suspending and resuming code in your pro

docs.swift.org


 

Concurrency (๋™์‹œ์„ฑ)

  • ๋น„๋™๊ธฐ ๋ฐ ๋ณ‘๋ ฌ ์ฝ”๋“œ์˜ ๊ตฌ์กฐ์  ์ž‘์„ฑ์„ ๋‚ด์žฅ ์ง€์›ํ•จ
  • ๋น„๋™๊ธฐ ์ฝ”๋“œ๋Š” ํ•œ๋ฒˆ์— ํ”„๋กœ๊ทธ๋žจ ํ•œ ์กฐ๊ฐ๋งŒ ์‹คํ–‰ํ•˜๊ธด ํ•˜์ง€๋งŒ, ์ž ์‹œ ๋ฉˆ์ท„๋‹ค ๋‚˜์ค‘์— ๋‹ค์‹œ ํ•  ์ˆ˜ ์žˆ๋‹ค. (ํ”„๋กœ๊ทธ๋žจ ์ฝ”๋“œ๋ฅผ ๋ฉˆ์ท„๋‹ค ๋‹ค์‹œํ•˜๋Š” ๊ฒƒ์€ ๋„คํŠธ์›Œํฌ ๋„ˆ๋จธ์˜ ์ž๋ฃŒ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ตฌ๋ฌธ ํ•ด์„ ๊ฐ™์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ, ์ž์‹ ์˜ UI๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋‹จ ๊ธฐ๊ฐ„ ์—ฐ์‚ฐ๋„ ๊ณ„์† ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.)
  • ๋ณ‘๋ ฌ ์ฝ”๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฝ”๋“œ ์กฐ๊ฐ์„ ๋™์‹œ์— ์‹คํ–‰ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • ๋น„๋™๊ธฐ, ๋ณ‘๋ ฌ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์€ ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ์—ฐ์‚ฐ์„ ์‹ค์‹œํ•˜๋ฉฐ, ์™ธ๋ถ€ ์‹œ์Šคํ…œ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์—ฐ์‚ฐ์€ ์ž ์‹œ ๋ฉˆ์ถ”๊ณ , ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ-์•ˆ์ „ํ•˜๊ณ  ๋” ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•˜๋„๋ก ํ•ด์ค€๋‹ค.
  • ๋ณ‘๋ ฌ ๋ฐ ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์ž„๋ฌด๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ์ž์›์„ ํ• ๋‹นํ•˜๋Š” ์ด๋Ÿฐ ํ–‰๋™์€, ๋ณต์žก๋„ ์ฆ๊ฐ€๋ผ๋Š” ๋Œ€๊ฐ€๊ฐ€ ๋”ฐ๋ฅธ๋‹ค.
  • ์Šค์œ„ํ”„ํŠธ๋Š” ์ž์‹ ์˜ ์˜๋„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ปดํŒŒ์ผ ์‹œ๊ฐ„์„ ๊ฒ€์‚ฌํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, actor๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•˜๊ฒŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ (mutable state)์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Š๋ฆฌ๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ์— ๋™์‹œ์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ๋นจ๋ผ์ง€๊ฑฐ๋‚˜, ์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋“œ๊ฐ€ ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค. ์‹ฌ์ง€์–ด ๋” ์–ด๋ ค์›Œ์งˆ ์ง€๋„ ๋ชจ๋ฅธ๋‹ค.
  • ํ•˜์ง€๋งŒ ๋™์‹œ์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋ฌธ์ œ๋ฅผ ์žก์•„๋‚ด๋„๋ก ๋„์šธ ์ˆœ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์ด์ „์— ๋™์‹œ์„ฑ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์•˜์œผ๋ฉด, ์“ฐ๋ ˆ๋“œ ์ž‘์—…์ด ์ต์ˆ™ํ• ์ง€๋„ ๋ชจ๋ฅธ๋‹ค. ์Šค์œ„ํ”„ํŠธ์˜ ๋™์‹œ์„ฑ ๋ชจ๋ธ์€ ์“ฐ๋ ˆ๋“œ ์œ„์—์„œ ์ œ์ž‘๋˜์—ˆ์ง€๋งŒ, ์ง์ ‘์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. ์Šค์œ„ํ”„ํŠธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋Š” ์ž์‹ ์ด ์‹คํ–‰์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ํฌ๊ธฐํ•˜์—ฌ, ์ฒซ๋ฒˆ์งธ ํ•จ์ˆ˜๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋™์•ˆ ๊ทธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋‹ค๋ฅธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

listPhotos(inGallery: "Summer Vacation") { photoNames in
  let sortedNames = photoNames.sorted()
  let name = sortedNames[0]
  downloadPhoto(named: name) { photo in
    show(photo)
  }
}

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


 

๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์ •์˜ํ•˜๊ณ  ํ˜ธ์ถœํ•˜๊ธฐ (async, await)

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

ํ•จ์ˆ˜๋‚˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋น„๋™๊ธฐ๋ผ๊ณ  ์ง€์‹œํ•˜๋ ค๋ฉด, throws ํ‚ค์›Œ๋“œ์™€ ๋น„์Šทํ•˜๊ฒŒ async ํ‚ค์›Œ๋“œ๋ฅผ ์ž์‹ ์˜ ์„ ์–ธ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋’ค์— ์ž‘์„ฑํ•œ๋‹ค. ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋‚˜ ๋ฉ”์„œ๋“œ๋ฉด async ๋ฅผ ๋ฐ˜ํ™˜ ํ™”์‚ดํ‘œ -> ์•ž์— ์ž‘์„ฑํ•œ๋‹ค.

func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... ์–ด๋– ํ•œ ๋น„๋™๊ธฐ ๋„คํŠธ์› ์ฝ”๋“œ ...
    return result
}

+) ๋น„๋™๊ธฐ์ด๋ฉด์„œ throws ๊นŒ์ง€ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋ฉด, throws ์•ž์— async๋ฅผ ์ž‘์„ฑ

๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š”, ๊ทธ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ์ž ์‹œ ๋ฉˆ์ถ˜๋‹ค. ํ˜ธ์ถœ ์•ž์— await ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž ์‹œ ๋ฉˆ์ถค ๊ฐ€๋Šฅ ์ง€์ ์„ ํ‘œ์‹œํ•œ๋‹ค. (์ด๋Š” ์—๋Ÿฌ๋ฉด ํ”„๋กœ๊ทธ๋žจ ํ๋ฆ„์ด ๋ฐ”๋€” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๊ณ  ํ‘œ์‹œํ•˜๊ณ ์ž throw ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ try๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ค.) ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ๋Š” ๋˜๋‹ค๋ฅธ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งŒ ์ž ์‹œ ๋ฉˆ์ถ˜๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ „์‹œ๊ด€์˜ ๋ชจ๋“  ์‚ฌ์ง„ ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ์—, ์ฒซ๋ฒˆ์งธ ์‚ฌ์ง„์„ ๋ณด์—ฌ์ฃผ๋Š” ์ฝ”๋“œ์ด๋‹ค.

let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = **await** downloadPhoto(named: name)
show(photo)

listPhotos(inGallery: ) ์™€ downloadPhoto(named: ) ํ•จ์ˆ˜ ๋‘˜ ๋‹ค ๋„คํŠธ์›ค ์š”์ฒญ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์™„๋ฃŒ ๊นŒ์ง€ ์ƒ๋Œ€์ ์œผ๋กœ ๊ธด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ async ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ๋น„๋™๊ธฐ๋กœ ๋งŒ๋“ค๋ฉด, ์œ„์˜ ์ฝ”๋“œ๊ฐ€ ์‚ฌ์ง„์ด ์ค€๋น„๋  ๋•Œ๊ฐ€์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๊ฐ€ ๊ณ„์† ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

์œ„ ์ฝ”๋“œ์˜ ๋™์‹œ์„ฑ์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•œ ์‹คํ–‰ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. ์œ„ ์ฝ”๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ์ค„์—์„œ ์‹คํ–‰์„ ์‹œ์ž‘ํ•˜๊ณ , ์ฒซ ๋ฒˆ์งธ await ๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค. ์ฆ‰ listPhotos(inGallery: ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์‹คํ–‰์„ ์ผ์‹œ์ •์ง€ํ•œ๋‹ค.
  2. 1๋ฒˆ ์ฝ”๋“œ ์‹คํ–‰์ด ์ผ์‹œ์ •์ง€๋˜๋Š” ๋™์•ˆ, ๋™์ผํ•œ ํ”„๋กœ๊ทธ๋žจ์˜ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ธ ์ƒˆ๋กœ์šด ์‚ฌ์ง„ ๊ฐค๋Ÿฌ๋ฆฌ ๋ชฉ๋ก์„ ๊ณ„์†ํ•ด์„œ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ์ฝ”๋“œ๋Š” await ๋กœ ํ‘œ์‹œ๋œ ๋‹ค์Œ ์ผ์‹œ์ •์ง€ ์ง€์ ๊นŒ์ง€ ํ˜น์€ ์‹คํ–‰ ์™„๋ฃŒ ๋  ๋•Œ๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค.
  3. listPhotos(inGallery: ) ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉด ์œ„ ์ฝ”๋“œ๋Š” ํ•ด๋‹น ์ง€์ ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๊ณ„์†ํ•ด์„œ ์‹คํ–‰๋œ๋‹ค. ์ฆ‰ await ์ฝ”๋“œ ๋‹ค์Œ์ค„์ธ, ๋ฐ˜ํ™˜๊ฐ’์„ photoNames์— ํ• ๋‹นํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.
  4. sortedNames ๋ฐ name ์„ ์ •์˜ํ•˜๋Š” ์ค„์€ ์ผ๋ฐ˜์ ์ธ ๋™๊ธฐ์ฝ”๋“œ ์ด๋ฏ€๋กœ, ๊ฐ€๋Šฅํ•œ ์ •์ง€ ์ง€์ ์€ ์—†๋‹ค.
  5. ๋‹ค์Œ await๋Š” downloadPhoto(named: ) ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ํ‘œ์‹œํ•œ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ ๋  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ๋‹ค์Œ ์ผ์‹œ์ •์ง€ํ•˜์—ฌ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ํ•œ๋‹ค.
  6. downloadPhoto ๋ฐ˜ํ™˜๊ฐ’์ด photos ์— ํ• ๋‹น๋˜๊ณ , slow(_:)๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋œ๋‹ค.

await๋กœ ํ‘œ์‹œ๋œ ์ฝ”๋“œ์˜ ๊ฐ€๋Šฅํ•œ ์ผ์‹œ์ •์ง€ ์ง€์ ์€ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ํ˜„์žฌ ์ฝ”๋“œ ๋ถ€๋ถ„์˜ ์‹คํ–‰์„ ์ผ์‹œ์ค‘์ง€ ํ•  ์ˆ˜ ์žˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ด๋ฅผ ์“ฐ๋ ˆ๋“œ ์–‘๋ณด(Yielding) ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๊ทธ ์ด์œ ๋Š” ์ฝ”๋“œ ์‹คํ–‰์„ ์ค‘๋‹จํ•˜๊ณ  ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. await ๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ๋Š” ์‹คํ–‰์„ ์ผ์‹œ์ •์ง€ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ, ํ”„๋กœ๊ทธ๋žจ์˜ ํŠน์ • ์œ„์น˜์—์„œ๋งŒ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๋˜๋Š” ํ”„๋กœํผํ‹ฐ์— ์žˆ๋Š” ์ฝ”๋“œ
  • @main ์œผ๋กœ ํ‘œ์‹œ๋œ ๊ตฌ์กฐ์ฒด, ํด๋ž˜์Šค, ์—ด๊ฑฐํ˜•์˜ static main() ๋ฉ”์„œ๋“œ์— ์žˆ๋Š” ์ฝ”๋“œ
  • ์ด๋ฒˆ ๊ธ€์˜ ์ดํ›„์— ๋‚˜์˜ฌ Unstructed Concurrency ์—์„œ ๋ณด๊ฒŒ ๋  ํ•˜์œ„ ์ž‘์—…์˜ ์ฝ”๋“œ

 

โ–ท ์ถ”๊ฐ€ note : Task.sleep(_:) ๋ฉ”์„œ๋“œ

func listPhotos(inGallery name: String) async -> [String] {
  await Task.sleep(2 * 1_000_000_000)  // 2์ดˆ
  return ["IMG001", "IMG99", "IMG0404"]
}
  • Task.sleep(_:) ๋ฉ”์„œ๋“œ๋Š” ๋™์‹œ์„ฑ ์ž‘๋™ ๋ฐฉ์‹์„ ๋ฐฐ์šฐ๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์•„๋ฌด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋ƒฅ ์‹œ๊ฐ„์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ๋„คํŠธ์›Œํฌ ์ž‘์—…์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ•˜๋Š” ๋“ฑ์˜ ์‹คํ—˜์„ ํ•ด๋ณด๊ณ  ์‹ถ์„ ๋•Œ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

๋น„๋™๊ธฐ ์‹œํ€€์Šค

์œ„ ์ฝ”๋“œ์—์„œ, listPhotos(inGallery: ) ๋ฉ”์„œ๋“œ๋Š” ๋ฐฐ์—ด์˜ ์š”์†Œ๊ฐ€ ์ค€๋น„๋œ ๋’ค ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ „์ฒด ๋ฐฐ์—ด์„ ํ•œ ๋ฒˆ์— ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋˜๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋น„๋™๊ธฐ ์‹œํ€€์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ ๋ฒˆ์— ์ปฌ๋ ‰์…˜์˜ ํ•œ ์š”์†Œ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค. ๋น„๋™๊ธฐ ์‹œํ€€์Šค์— ๋Œ€ํ•œ ๋ฐ˜๋ณต ๋™์ž‘์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

import Foundation

let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
  print(line)
}

ํ‰๋ฒ”ํ•œ for-in ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ , ์œ„ ์—์ œ์—์„œ๋Š” for ๋‹ค์Œ await ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋น„๋™๊ธฐ ํ•จ์ˆ˜์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ await ํ‚ค์›Œ๋“œ๋กœ ์ž ์‹œ ๋ฉˆ์ถ”๋Š” ์ง€์ ์„ ์ง€์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. for-await-in ๋ฐ˜๋ณต๋ฌธ์€ ๋‹ค์Œ ์›์†Œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ  ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค.

์ง์ ‘ ๋งŒ๋“  sequence ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์„ for-in ๋ฃจํ”„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ AsyncSequence ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์„œ for-await-in ๊ตฌ๋ฌธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.


 

๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋ณ‘๋ ฌ(Parallel)๋กœ ํ˜ธ์ถœํ•˜๊ธฐ

await๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•œ ๋ฒˆ์˜ ํ•˜๋‚˜์˜ ์ฝ”๋“œ๋งŒ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ํ˜ธ์ถœ์ž๋Š” ๋‹ค์Œ ์ฝ”๋“œ ์ค„์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ์ด๋™ํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐค๋Ÿฌ๋ฆฌ์—์„œ ์ฒ˜์Œ ์„ธ ์žฅ์˜ ์‚ฌ์ง„์„ ๊ฐ€์ง€๊ณ  ์˜ค๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด downloadPhoto(named: ) ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์„ธ ๋ฒˆ์˜ ํ˜ธ์ถœ์„ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋‹ค.

let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])

let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)

์ด๋Ÿฐ ์ ‘๊ทผ ๋ฐฉ์‹์—๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. download๊ฐ€ ๋น„๋™๊ธฐ๋ผ์„œ ์ง„ํ–‰ ๋™์•ˆ ๋‹ค๋ฅธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธด ํ•˜์ง€๋งŒ, downloadPhoto(named: ) ์˜ ํ˜ธ์ถœ์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ๋งŒ ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. (์ฒ˜์Œ์ฝ”๋“œ ์ง„ํ–‰, ๋‘๋ฒˆ์งธ ์ฝ”๋“œ ์ง„ํ–‰...await๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰)

์šฐ๋ฆฌ๋Š” ์ด ์ฝ”๋“œ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜๊ธธ ๋ฐ”๋ž€๋‹ค. ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์ž๊ธฐ ์ฃผ๋ณ€์˜ ์ฝ”๋“œ์™€ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜๊ฒŒ๋” ํ•˜๋ ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด let ์•ž์— async ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค์Œ, await ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด๋œ๋‹ค.

async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])

let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)

์ด ์˜ˆ์ œ์—์„œ๋Š” ์„ธ downloadPhoto(named: ) ํ˜ธ์ถœ์€ ๋ชจ๋‘ ์ด์ „๊ฒŒ ์™„๋ฃŒํ•˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋™์‹œ์— ์‹œ์ž‘ํ•œ๋‹ค. ์ด ๋ฐฉ์‹์—์„œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ await๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒƒ์€, ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ์ž ์‹œ ๋ฉˆ์ถ”์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ ๋Œ€์‹ , photos ๋ฅผ ์ •์˜ํ•œ ์ค„๊นŒ์ง€ ์‹คํ–‰์„ ๊ณ„์†ํ•˜๊ฒŒ ๋œ๋‹ค. photos๋ฅผ ์„ ์–ธํ•˜๋Š” ์‹œ์ ์—๋Š” ์‚ฌ์ง„๋“ค์ด ๋ชจ๋‘ ๋‹ค์šด๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ, await ๋ฅผ ์ž‘์„ฑํ•ด์„œ ๊ธฐ๋‹ค๋ ค์ค˜์•ผํ•œ๋‹ค.

์œ„ ๋‘๊ฐœ์˜ ์ ‘๊ทผ๋ฒ•์˜ ์ฐจ์ด์ ์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋‹ค์Œ ์ค„ ์ฝ”๋“œ๊ฐ€ ๊ทธ ํ•จ์ˆ˜ ๊ฒฐ๊ณผ์— ์˜์กดํ•  ๋•Œ, await ๋กœ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.์ด๋Š” ์ˆœ์ฐจ์ ์œผ๋กœ ์‹ค์‹œํ•˜๋Š” ์ž‘์—…์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ์ฝ”๋“œ ๋‚˜์ค‘์—์„œ์•ผ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋Š”, async-let ์œผ๋กœ ๋น„๋™๊ธฐํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋Š” ๋ณ‘๋ ฌ๋กœ ์‹ค์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์„ ์ƒ์„ฑํ•œ๋‹ค.
  • await์™€ async-let ๋‘˜ ๋‹ค ์ž์‹ ์ด ๋ฉˆ์ถ˜ ๋™์•ˆ ๋‹ค๋ฅธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•œ๋‹ค.
  • ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘, ์ž ์‹œ ๋ฉˆ์ถค ๊ฐ€๋Šฅ ์ง€์ ์„ await ๋กœ ํ‘œ์‹œํ•˜์—ฌ, ํ•„์š”ํ•˜๋‹ค๋ฉด ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋  ๋•Œ๊นŒ์ง€ ์ผ์‹œ์ •์ง€ํ•˜๋Š” ๊ฒƒ์„ ์ง€์‹œํ•œ๋‹ค.

 

Tasks and Task Groups

**์ž‘์—…(task)**๋Š” ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—… ๋‹จ์œ„์ด๋‹ค. ๋ชจ๋“  ๋น„๋™๊ธฐ ์ฝ”๋“œ๋Š” ์–ด๋– ํ•œ ์ž„๋ฌด์˜ ์ผ๋ถ€๋ถ„์œผ๋กœ์จ ์‹คํ–‰ํ•œ๋‹ค. ์ด์ „ ์„น์…˜์—์„œ ์„ค๋ช…ํ•œ async-let ๊ตฌ๋ฌธ์€ ์ž์‹ ์ž‘์—…์„ ์ƒ์„ฑํ•œ๋‹ค. ๋˜ํ•œ ์ž‘์—… ๊ทธ๋ฃน์„ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ๊ทธ๋ฃน์— ํ•˜์œ„ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์šฐ์„ ์ˆœ์œ„์™€ ์ทจ์†Œ๋ฅผ ์ž˜ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ณ  ๋™์ ์ธ ์ˆ˜์˜ ์ž‘์—…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

์ž‘์—…์€ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ •๋ ฌ๋œ๋‹ค. ์ž‘์—… ๊ทธ๋ฃน์˜ ๊ฐ ์ž‘์—…์—๋Š” ๋™์ผํ•œ ์ƒ์œ„ ์ž‘์—…์ด ์žˆ์œผ๋ฉฐ, ๊ฐ ์ž‘์—…์—๋Š” ํ•˜์œ„ ์ž‘์—…์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์ž‘์—…๊ณผ ์ž‘์—… ๊ทธ๋ฃน ๊ฐ„์˜ ๋ช…์‹œ์ ์ธ ๊ด€๊ณ„ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ •ํ™•์„ฑ์— ๋Œ€ํ•œ ์ฑ…์ž„ ์ค‘ ์ผ๋ถ€๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ด๋‹นํ•˜์ง€๋งŒ, ์ž‘์—… ๊ฐ„์˜ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋Š” ์ทจ์†Œ ์ „ํŒŒ์™€ ๊ฐ™์€ ์ผ๋ถ€ ๋™์ž‘์„ ์Šค์œ„ํ”„ํŠธ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•˜๋ฉฐ, ์ปดํŒŒ์ผ ์—๋Ÿฌ๋„ ์Šค์œ„ํ”„ํŠธ๊ฐ€ ํƒ์ง€ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

await withTaskGroup(of: Data.self) { taskGroup in
  let photoNames = await listPhotos(inGallery: "Summer Vacation")
  for name in photoNames {
    taskGroup.async { await downloadPhoto(named: name) }
    }
}

Task Group ์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ์—ฌ๊ธฐ(click) ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๋” ์•Œ์•„๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค.

 

Unstructured Concurrency

Structured Cocurrency ์™€ ๋™์‹œ์— swift๋Š” unstructured Concurrency ๋„ ์ง€์›ํ•œ๋‹ค. task group ์˜ task์™€๋Š” ๋‹ค๋ฅด๊ฒŒ, Unstructured task๋Š” ๋ถ€๋ชจ task ๊ฐ€ ์—†๋‹ค. ์ž์œ ๋กญ๊ฒŒ unstructured task๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ •ํ™•์„ฑ์— ๋Œ€ํ•ด์„œ๋Š” ์ฑ…์ž„์„ ์š”๊ตฌํ•œ๋‹ค. ํ˜„์žฌ actor์— unstructured task ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด, async(priority: operation: ) ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

detached task ๋ผ ๋ถˆ๋ฆฌ๋Š” ํ˜„์žฌ actor์— ํฌํ•จ๋˜์ง€ ์•Š๋Š” unstructured task ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด, asyncDetached(priority: operation: ) ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” task์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ์ทจ์†Œํ•˜๋Š” ์ž‘์šฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” task.handle ์— ๊ด€ํ•œ ์˜ˆ์ œ์ด๋‹ค.

let newPhoto = // ... ์–ด๋– ํ•œ ์‚ฌ์ง„ ์ž๋ฃŒ ...
let handle = async {
  return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}
let result = await handle.get()

 

Task Cancellation

์Šค์œ„ํ”„ํŠธ ๋™์‹œ์„ฑ์€ ํ˜‘๋ ฅ ์ทจ์†Œ ๋ชจ๋ธ (cooperative cancellation model)์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฐ๊ฐ์˜ task๋Š” ์‹คํ–‰์ค‘์— cancel ๋˜์—ˆ๋Š”์ง€ cancellation์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์‘๋‹ต์„ ์ฃผ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • CancellationError์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ throw
  • nil ๋˜๋Š” ๋นˆ ์ปฌ๋ ‰์…˜ ๋ฐ˜ํ™˜
  • ๋ถ€๋ถ„์ ์œผ๋กœ ์™„๋ฃŒ๋œ ์ž‘์—…์„ ๋ฐ˜ํ™˜

Cancellation์„ ์ฒดํฌํ•˜๋ ค๋ฉด

  • CancellationError๋ฅผ throw ํ•˜๋Š” Task.checkCancellation()์„ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜
  • Task.isCancelled์˜ ๊ฐ’์„ ์ฒดํฌํ•˜๊ณ  ํ•ธ๋“ค๋ง

ํ•˜๋ฉด ๋œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ๊ฐค๋Ÿฌ๋ฆฌ์—์„œ ์‚ฌ์ง„์„ ๋‹ค์šด๋กœ๋“œํ•˜๋Š” task๋Š” ๋ถ€๋ถ„ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ๋‹ซ์•„์•ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ทจ์†Œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ•˜๋ ค๋ฉด Task.Handle.cancel()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.


 

Actors

์œ„์—์„œ ์ˆ˜์—†์ด ๋‚˜์˜จ actor์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์•Œ์•„๋ณด์ž.

  • actor์€ ํด๋ž˜์Šค์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฐธ์กฐํƒ€์ž…์ด๋‹ค.
  • ํด๋ž˜์Šค์™€ ๋‹ฌ๋ฆฌ actor์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉ
actor TemperatureLogger {
  let label: String
  var measurements: [Int]
  private(set) var max: Int

  init(label: String, measurement: Int) {
    self.label = label
    self.measurements = [measurement]
    self.max = measurement
  }
}

์œ„ ์ฝ”๋“œ๋Š” TemperatureLogger ๋ผ๋Š” actor๋Š” actor ๋ฐ–์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ๋‚ด๋ถ€ ์ ‘๊ทผ๋งŒ ๊ฐ€๋Šฅํ•œ max ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋‹ค.

๊ตฌ์กฐ์ฒด ๋ฐ ํด๋ž˜์Šค์˜ ๋™์ผํ•œ ์ƒ์„ฑ์ž ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ Actor ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. Actor์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ์— ์ ‘๊ทผํ•  ๋•Œ, ์‚ฌ์šฉํ•˜์—ฌ ์ž ์žฌ์ ์ธ ์ •์ง€ ์ง€์ ์„ ํ‘œ์‹œํ•œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
// "25" ๋ฅผ ์ธ์‡„ํ•จ

์ด ์˜ˆ์ œ์—์„œ, logger.max์˜ ์ ‘๊ทผ์€ ์ž ์žฌ์ ์ธ ์ค‘๋‹จ ํฌ์ธํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. actor๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ๋ณ€๊ฒจ ใ…‡๊ฐ€๋Šฅํ•œ ์ƒํƒœ์— ์—‘์„ธ์Šค ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์•ฝ ์ฝ”๋“œ๊ฐ€ ๋‹ค๋ฅธ task ์™€ ์ƒํ˜ธ์ž‘์šฉ ์ค‘์ด๋ผ๋ฉด, ์ด ํ”„๋กœํผํ‹ฐ์˜ ์ ‘๊ทผ์— ์ œํ•œ๋œ๋‹ค. ๋งˆ์น˜ lock, semaphore ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

๋Œ€์กฐ์ ์œผ๋กœ actor์˜ ์ฝ”๋“œ์—์„œ๋Š” actor์˜ ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•  ๋•Œ await๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.

extension TemperatureLogger {
  func **update**(with measurement: Int) {
    measurements.append(measurement)
    if measurement > max {
      max = measurement
    }
  }
}

์ด ์ฝ”๋“œ๋Š” TempertureLogger๋ฅผ ์ƒˆ๋กœ์šด ์˜จ๋„๋กœ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

update(with: ) ๋ฉ”์„œ๋“œ๋Š” actor์—์„œ ์ด๋ฏธ ๋™์ž‘ํ•˜๊ณ  ์žˆ๊ณ , max์™€ ๊ฐ™์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ ‘๊ทผํ•  ๋•Œ await๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋Š” ์™œ actor๊ฐ€ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์— ์—‘์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ด์œ ์ด๋‹ค. actor์˜ ์ƒํƒœ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๋Š” ์ผ์‹œ์ ์œผ๋กœ ๋ถˆ๋ณ€๋Ÿ‰์„ ํ•ด์†Œ์‹œํ‚จ๋‹ค. TempertureLogger ์—‘ํ„ฐ๋Š” ์˜จ๋„ ๋ชฉ๋ก๊ณผ ์ตœ๋Œ€ ์˜จ๋„๋ฅผ ์ถ”์ ํ•˜๊ณ  ์ƒˆ๋กœ์šด ์ธก์ •๊ฐ’์„ ๊ธฐ๋กํ•  ๋•Œ ์ตœ๋Œ€ ์˜จ๋„๋ฅผ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค. ์—…๋ฐ์ดํŠธ ๋„์ค‘์— ์ƒˆ๋กœ์šด ์ธก์ •์ด ์ถ”๊ฐ€๋˜๋ฉด, ์ด๋Š” logger์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜์—ฌ ์ด๋ฅผ ๋ฐฉ์ง€ํ•ด์•ผํ•œ๋‹ค. ์•„๊นŒ์˜ ๋ฌธ์ œ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ์ฝ”๋“œ๋Š” update(with: ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ๋จผ์ € measurements ๋ฐฐ์—ด์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.
  • ์ฝ”๋“œ์—์„œ ์ตœ๋Œ€๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ ์ „์— ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ ์ตœ๋Œ€๊ฐ’๊ณผ ์˜จ๋„ ๋ฐฐ์—ด์„ ์ฝ๋Š”๋‹ค.
  • ์ฝ”๋“œ๋Š” ์ตœ๋Œ€๊ฐ’์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์—…๋ฐ์ดํŠธ๋ฅผ ์™„๋ฃŒํ•œ๋‹ค.

์œ„์™€ ๊ฐ™์€ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ๋Š” ๋ถ€์ •ํ™•ํ•œ ์ •๋ณด์— ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค. Swift Actor ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. Actor๋Š” ํ•œ ์ง€์ ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ํ—ˆ์šฉํ•˜๊ณ  ํ•ด๋‹น ์ฝ”๋“œ๋Š” await๋กœ ์ •์ง€ ๊ฐ€๋Šฅํ•œ ์ง€์ ์„ ํ‘œ์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. update(with; )๋Š” ์ค‘๋‹จ ์ง€์ ์„ ํฌํ•จํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์ฝ”๋“œ๋Š” ์—…๋ฐ์ดํŠธ ๋„์ค‘ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์—์„œ์™€ ๊ฐ™์ด Actor ์™ธ๋ถ€์—์„œ ์ด๋Ÿฌํ•œ ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

print(logger.max)  // ์—๋Ÿฌ

await ์ž‘์„ฑ ์—†์ด logger.max ์— ์ ‘๊ทผํ•˜๋ฉด ์‹คํŒจํ•˜๋Š”๋ฐ ์•กํ„ฐ์˜ ์†์„ฑ์€ ๊ทธ ์•กํ„ฐ์˜ ๊ฒฉ๋ฆฌ๋œ ์ง€์—ญ ์ƒํƒœ (isolated local state) ์˜ ์ผ๋ถ€์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์Šค์œ„ํ”„ํŠธ๋Š” ์•กํ„ฐ ์•ˆ์˜ ์ฝ”๋“œ๋งŒ ์•กํ„ฐ์˜ ์ง€์—ญ ์ƒํƒœ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ณด์ฆํ•œ๋‹ค.์ด ๋ณด์ฆ์„ actor isolation ์ด๋ผ๊ณ  ํ•œ๋‹ค.

 

 

โ–ถ ์ถ”๊ฐ€๋กœ ์ฝ์–ด ๋ณผ ์ž๋ฃŒ - ๊ณต๋ถ€๋Š” ๋๋„์—†๋‹ค์•„์•„์•„ ์ฝ๊ณ  ์ •๋ฆฌํ•ด๋ณด์ž.

https://engineering.linecorp.com/ko/blog/about-swift-concurrency/

 

Swift Concurrency์— ๋Œ€ํ•ด์„œ - LINE ENGINEERING

์•ˆ๋…•ํ•˜์„ธ์š”. iOS Platform Dev ํŒ€์˜ ๊น€์œค์žฌ์ž…๋‹ˆ๋‹ค. ์•ฑ์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด์„œ๋Š” ์•Œ๋งž์€ ๋™์‹œ์„ฑ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜จ๋ณด๋”ฉ ์Šคํ„ฐ๋””์—์„œ๋Š” ๊ธฐ์กด์— Swift์—์„œ ๋™์‹œ์„ฑ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š”

engineering.linecorp.com

https://studyin-mysparetime.tistory.com/4

 

WWDC21 Explore structured concurrency in Swift

WWDC21 Explore structured concurrency in Swift Swift 5.5์—์„œ ์ƒˆ๋กœ์šด ๋™๊ธฐํ™” ๊ธฐ๋ฒ•์„ ์†Œ๊ฐœํ•œ๋‹ค. ๊ตฌ์กฐ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(structured programming)์—์„œ ์˜๊ฐ์„ ์–ป์–ด Structured concurrency๋ฅผ ๊ฐœ๋ฐœํ–ˆ๋‹ค. Let's d..

studyin-mysparetime.tistory.com

 

๋ฐ˜์‘ํ˜•