Published on

๐ŸŽ Swift - Concurrency

Authors
  • avatar
    Name
    ์ด์ฐฝ์ค€
    Twitter

Concurrency

WWDC21์˜ ์ฃผ์š” ์ฃผ์ œ๋Š” Concurrency๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

21๋…„์— ์ฒ˜์Œ ๊ณต๊ฐœ๋œ ํ›„ ๊ด€๋ จ๋œ ํฌ์ŠคํŠธ๋„ ๋งŽ์•„์กŒ๊ณ  ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋„ ๋Œ€์‘ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋งŽ์ด ์ด๋ฃจ์–ด์ง„ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

์ด์ œ ์Šฌ์Šฌ ์‹ค๋ฌด์— ์‚ฌ์šฉ๋˜๋Š” ๋ชจ์Šต๋“ค๋„ ๋ณด์ด๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์–ด๋ ดํ’‹์ด โ€œasync์™€ await๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ๋ฒ•์ด๋‹ค.โ€ ์ •๋„๋กœ๋งŒ ์•Œ์•„๋‘๊ณ  ๋‚˜์ค‘์— ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค ์ƒ๊ฐํ–ˆ์ง€๋งŒ ํ”„๋กœ์ ํŠธ์—์„œ callback ์ง€์˜ฅ์„ ๋ณธ ์ˆœ๊ฐ„.. ํ•™๊ตฌ์—ด์ด ์˜ฌ๋ผ ํ•œ ๋ฒˆ ํ•™์Šตํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

WWDC21์˜ ์„ธ์…˜๋“ค์„ ์‚ดํŽด๋ณด์•˜๋”๋‹ˆ ๊ด€๋ จ ์„ธ์…˜๋งŒ ๊ฑฐ์˜ 10๊ฐœ์— ๋‹ฌํ•˜๊ณ  ํ•˜๋‚˜ํ•˜๋‚˜์˜ ๋‚ด์šฉ๋“ค๋„ ๊ฝ‰ ์ฐฌ 20~30๋ถ„ ์ •๋„๋ฅผ ์ด๋ฃจ๊ณ  ์žˆ๋”๊ตฐ์š”..

๊ทธ๋ž˜์„œ ๋‚ด์šฉ์ด ๋ฌด์ง€๋ฌด์ง€ ๋งŽ์Šต๋‹ˆ๋‹ค.. ๐Ÿซ 

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

๋น„๋™๊ธฐ ์ฝ”๋“œ๋Š” โ€œ๋‚˜์ค‘์— ์–ธ์  ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์‹คํ–‰๋  ์ฝ”๋“œโ€ ์ž…๋‹ˆ๋‹ค.

๊ทธ ์‹œ๊ธฐ๋Š” ๋ณด์žฅ๋˜์ง€ ์•Š์œผ๋ฉฐ ์ˆœ์„œ ๋˜ํ•œ ๋ณด์žฅ๋˜์ง€ ์•Š์„ ๋•Œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Swift์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ GCD๋ผ๊ณ  ๋ถ€๋ฅด๋Š” DispatchQueue๋ฅผ ํ†ตํ•ด ์ง€์›ํ•˜๋Š” ๊ฐœ๋…์ด์˜€์ฃ .

print("1")
DispatchQueue.main.async {
  print("2")
}
print("3")

์œ„ ์ฝ”๋“œ์˜ print("2") ๊ตฌ๋ฌธ์€ ๋น„๋™๊ธฐ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ˆœ์„œ์™€ ํ˜ธ์ถœ ์‹œ๊ธฐ๊ฐ€ ๋ถˆํ™•์‹คํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”๋กœ ํ˜ธ์ถœ๋ ์ˆ˜๋„ ์žˆ๊ณ  ์•„๋‹์ˆ˜๋„ ์žˆ์ฃ .

1 2 3

1 3 2

๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์ด ์‹คํ–‰๋งˆ๋‹ค ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅผ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ์ฝ”๋“œ๋Š” 1. ํ•ด๋‹น ๋ผ์ธ์— ๋„๋‹ฌ๋˜๋„ ๋ฐ”๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ , 2. ์ดํ›„์— ์žˆ๋Š” ์ฝ”๋“œ์˜ ์‹คํ–‰์„ Blockingํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ์–ธ์ œ ์‹คํ–‰๋˜๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค๋ฉด, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‚ฐ์ถœ๋œ ์–ด๋–ค ๊ฐ’์„ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ์š”?

๋‹คํ–‰ํžˆ๋„ ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ์‹œ์ ์€ ์šฐ๋ฆฌ๊ฐ€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@escaping ํด๋กœ์ €๋ฅผ ํ†ตํ•ด์„œ์š”.

func foo() {
  print("1")
  asyncFoo(completion: { value in
    print(value)
  })
  print("3")
}

func asyncFoo(completion: @escaping (String) -> Void) {
  DispatchQueue.main.async {
    let a = "2"
    completion(a)
  }
}

asyncFoo ๋ฉ”์„œ๋“œ์—์„œ completion ํด๋กœ์ €๋Š” async ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ์‹œ์ ์— ํ˜ธ์ถœ๋˜์–ด ์ฝœ๋Ÿฌ์ธ foo ๋ฉ”์„œ๋“œ์— String ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ value๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ฐฉ์‹์˜ ๋ฌธ๋ฒ•์€ ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ๋๋‚ฌ์„ ๋•Œ์˜ ๋™์ž‘๋“ค์˜ ๋ฌถ์Œ์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ชจ์•„๋‘˜ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ (์žฅ์ ์ธ๊ฐ€..?) callback ์ง€์˜ฅ๊ณผ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ๋ฌธ์ œ์ ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

GCD์˜ ์ง„์งœ ๋ฌธ์ œ์ 

์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ฃผ๋Š” ๋ถˆ์พŒํ•œ ๊ฒฝํ—˜๋„ ์ค‘์š”ํ•˜์ง€๋งŒ GCD์—๋Š” ๋”์šฑ ํฌ๋ฆฌํ‹ฐ์ปฌํ•œ ๋‹จ์ ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”๋กœ CPU์˜ ๋ถˆํ•„์š”ํ•œ ์ถ”๊ฐ€ ๋™์ž‘๊ณผ ๊ณผ๋„ํ•œ ๋ฆฌ์†Œ์Šค์˜ ์‚ฌ์šฉ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ธ์ง€ ์‚ดํŽด๋ณผ๊นŒ์š”?

DispatchQueue์— ๋™์ž‘์ด enqueue๋˜๋ฉด, ์‹œ์Šคํ…œ์€ ํ•ด๋‹น ์ž‘์—…์ด ์ˆ˜ํ–‰๋  ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์ˆ˜ํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ๋™์ž‘๋“ค์ด enqueue๋˜๋ฉด, ์‹œ์Šคํ…œ์€ ํ•ด๋‹น ๋™์ž‘๋“ค์„ ๋™์‹œ์— ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. CPU์˜ ์ฝ”์–ด๊ฐ€ ๋” ์ด์ƒ์˜ ์“ฐ๋ ˆ๋“œ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€์š”.

์ฝ”์–ด๊ฐ€ 2๊ฐœ์ธ ํ™˜๊ฒฝ์—์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ƒํ™ฉ

ํ•˜๋‚˜์˜ ์ฝ”์–ด๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ด์œ ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

  1. ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ Block๋˜๋”๋ผ๋„ ์ฝ”์–ด๊ฐ€ ์‰ฌ์ง€์•Š๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด
  2. ์“ฐ๋ ˆ๋“œ๊ฐ„์˜ Race Condition์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด (Semaphore ์ฐธ๊ณ )

๊ทธ๋Ÿฐ๋ฐ ๊ณผ์—ฐ Blocking๋œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋งŽ์•„์ง„๋‹ค๊ณ  ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฌด์ˆ˜ํžˆ ๋งŽ์ด ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์ด ํ•ญ์ƒ ์ข‹์„๊นŒ์š”?

๋‹น์—ฐํžˆ ์•„๋‹ˆ๊ฒ ์ฃ ..

์“ฐ๋ ˆ๋“œ๋“ค์ด Blocking๋œ ์ƒํƒœ์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ณ„์† ๋ถˆ๋Ÿฌ์˜จ๋‹ค๋ฉด, ๋” ์ด์ƒ ์ฝ”์–ด๊ฐ€ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†๋Š” ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ํ˜„์ƒ์„ Thread Explosion์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

Swift๋Š” ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด DispatchSemaphore์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ์— ๋„ˆ๋ฌด ๋ฒˆ๊ฑฐ๋กญ๋‹ค๋Š” ๊ฒƒ์ด์ฃ ..!

Thread Explosion ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋ฉด OS๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ๋งˆ์ฃผ์นฉ๋‹ˆ๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ

Block๋œ ์“ฐ๋ ˆ๋“œ๋Š” ๊ฐ์ž ๋ฉ”๋ชจ๋ฆฌ์™€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ๊ฑฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ unlock์„ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ๊ฑฐํ•˜๊ณ  ์žˆ์„ ์ˆ˜๋„ ์žˆ์ฃ .

  • ์Šค์ผ€์ค„๋ง ์˜ค๋ฒ„ํ—ค๋“œ

CPU์˜ ์ฝ”์–ด๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ„์˜ ์ „ํ™˜์„ ์œ„ํ•ด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ(Context Switching) ์ด๋ผ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์“ฐ๋ ˆ๋“œ๊ฐ€ ํญ๋ฐœ์ ์œผ๋กœ ๋งŽ์•„์ง€๋ฉด ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ๋„ ๋นˆ๋ฒˆํžˆ ์ผ์–ด๋‚˜ ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์ด ๋Š˜์–ด๋‚ฉ๋‹ˆ๋‹ค.

์ž ๊ทธ๋ž˜์„œ Swift๋Š” ์ด๋Ÿฐ ํ˜„์ƒ์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š๋ƒ?

async / await

์ƒˆ๋กœ์šด Swift์˜ asynchronous ๊ฐœ๋… async / await์™€ concurrency๋ฅผ ํ†ตํ•ด์„œ์ฃ .

์‹ค์€ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋”ฉ์˜ ์ด๋Ÿฌํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๋“ค์€ ์ด์ „๋ถ€ํ„ฐ ๋‹ค์–‘ํ•œ ์–ธ์–ด์™€ ์šด์˜์ฒด์ œ ์ „๋ฌธ๊ฐ€๋“ค์—๊ฒŒ ๋ฌธ์ œ์‹œ ๋˜์–ด์™”์Šต๋‹ˆ๋‹ค.

์ด๋“ค์ด ์ œ์‹œํ•œ ๋ฐฉ๋ฒ•์€ ๋ฐ”๋กœ Coroutine ๋ฐฉ์‹์ด์˜€์Šต๋‹ˆ๋‹ค.

์˜ค๋ž˜์ „ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ ๋ฐฉ์‹์ด ์ œ์‹œ๋˜๊ณ  ํ†ต์šฉ๋˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉฐ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฒ„๋ ค์กŒ๋˜ Coroutine ๋ฐฉ์‹์ด ํ˜„๋Œ€์— ์™€์„œ ๋‹ค์‹œ ์—ฐ๊ตฌ๋˜๊ณ  ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์ฃ .

์‹ค์ œ๋กœ Python, Kotlin๊ณผ ๊ฐ™์€ ์–ธ์–ด๋“ค์ด ์ ๊ทน์ ์œผ๋กœ Coroutine ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Coroutine ๋ฐฉ์‹์€ ์–ด๋–ค ๋ฐฉ์‹์ด๋ƒ?

์ฝ”๋ฃจํ‹ด(Coroutine) ์€ CPU์˜ ์ฝ”์–ด ๊ฐœ์ˆ˜๋งŒํผ๋งŒ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์“ฐ๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋Œ€์‹  ์ž‘์—…์„ ๋ง‰์•„๋‘ ์œผ๋กœ์จ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

Swift ์šฉ์–ด๋กœ ๋ฐ”๊พธ์–ด๋ณผ๊นŒ์š”?

Swift Concurrency๋Š” ์“ฐ๋ ˆ๋“œ์˜ ์ฐจ๋‹จ(Blocking)์„ ์—†์• ๊ณ  ์ž‘์—…์˜ ์žฌ์‹คํ–‰(Resumption of Work)๋ฅผ ์ถ”์ ํ•˜๋Š” continuation์ด๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด Context Switching ๋Œ€์‹  ๊ฐ™์€ ์“ฐ๋ ˆ๋“œ ๋‚ด์—์„œ Continuation Switching์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ž Concurrency๊ฐ€ (๋ชจ์ˆœ์ ์ด๊ฒŒ๋„) ํ˜„๋Œ€์ ์ด๊ณ  ์ข‹๋‹ค๋Š” ๊ฑด ์•Œ์•˜์–ด์š”.

๊ทธ๋ž˜์„œ async / await์€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ์š”? ๐Ÿ˜’

WWDC์—์„œ๋„ ์‚ฌ์šฉํ•œ ๊ธฐ์กด์˜ @escaping ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ๊ฐ€์ ธ์™€๋ดค์–ด์š”.

์‹œ์Šคํ…œ์ ์ธ ๋‹จ์  ๋ง๊ณ  ์ฝ”๋“œ ์ž‘์„ฑ์˜ ์ธก๋ฉด์—์„œ @escaping ํด๋กœ์ € ๋ฐฉ์‹์€ ์„ธ๊ฐ€์ง€ ๋‹จ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  1. completion ํด๋กœ์ € ํ˜ธ์ถœ์„ ๊นŒ๋จน๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. (์—ฌ๋Ÿฌ๊ตฐ๋ฐ์— ํ•„์š”)
  2. callback์ด ์ค‘์ฒฉํ•ด์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.
  3. ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

์ž ๊ทธ๋Ÿฐ๋ฐ async / await๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋กœ ๋ฐ”๊ฟ”๋ณด๋ฉด์š”?

์—„์ฒญ ์งง์•„์ง€๊ณ  ์ˆ˜๋งŽ์•˜๋˜ ์ค‘๊ด„ํ˜ธ๋“ค์ด ์‚ฌ๋ผ์กŒ์–ด์š”! ๐Ÿ‘

async

ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฐ˜ํ™˜ํƒ€์ž… ์ค‘๊ฐ„์— async ๋ฅผ ๋ถ™์—ฌ์คŒ์œผ๋กœ์จ ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ๋น„๋™๊ธฐ์ ์ด๋‹ค ๋ผ๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด์ค๋‹ˆ๋‹ค!

throws๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋ผ๋Š” ๊ฒƒ๋„ ํ•จ๊ป˜ ๋ช…์‹œํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

await

async๋กœ ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Concurrent Context ๋‚ด๋ถ€์—์„œ await ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

let (data, response) = try await URLSession.shared.data(for: request)

์ฃผ์˜ํ•  ์ ์€ ์ •์˜ํ• ๋•Œ๋Š” ์ˆœ์„œ๊ฐ€ async throws์ง€๋งŒ, ์‚ฌ์šฉํ• ๋•Œ๋Š” try await ์ˆœ์„œ๋ผ๋Š” ๊ฒƒ์„ ์•Œ์•„๋‘์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

await ํ‚ค์›Œ๋“œ๋Š” ํ•ด๋‹น ๋ผ์ธ์ด Suspension Point๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Suspend

await ํฌ์ธํŠธ๋ฅผ ๋งŒ๋‚˜๋ฉด ๋œ๋‹ค๋Š” Suspend๋Š” ๋˜ ๋ญ˜๊นŒ์š”?

Suspend๋Š” โ€œํ•ด๋‹น ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์Šค๋ ˆ๋“œ์˜ ํ†ต์ œ๊ถŒ์„ ์‹œ์Šคํ…œ์—๊ฒŒ ๋„˜๊ฒจ์ค€๋‹คโ€ ๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ synchronousํ•œ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ์—๋Š” ์œ„์™€ ๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

fetchThumbnail ํ•จ์ˆ˜์—์„œ thumbnailURLRequest ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋•Œ ๋‘ ํ•จ์ˆ˜ ๋ชจ๋‘ sync ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— fetchThumbnail ํ•จ์ˆ˜๋Š” thumbnailURLRequest ํ•จ์ˆ˜์—๊ฒŒ ์“ฐ๋ ˆ๋“œ ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ์ค๋‹ˆ๋‹ค.

thumbnailURLRequest ํ•จ์ˆ˜๋Š” ์ˆ˜ํ–‰์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜๊ณ  ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ œ์–ด๊ถŒ์„ ๋‹ค์‹œ Caller์ธ fetchThumbnail ํ•จ์ˆ˜์—๊ฒŒ ๋Œ๋ ค์ค๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ์“ฐ๋ ˆ๋“œ๋Š” ์ด ๋‘ ์ž‘์—… ์™ธ์˜ ๋‹ค๋ฅธ ์ž‘์—…๋“ค์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

asynchronousํ•œ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–จ๊นŒ์š”?

fetchThumbnail ํ•จ์ˆ˜๊ฐ€ data(for: request) ํ•จ์ˆ˜์—๊ฒŒ ์“ฐ๋ ˆ๋“œ ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฒƒ๊นŒ์ง€๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ await๋กœ ๋ช…์‹œ๋œ data(for: request) ํ•จ์ˆ˜๋Š” async ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๊ฐ„์— suspend ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

async ํ•จ์ˆ˜๊ฐ€ suspend๋˜๋ฉด, ์“ฐ๋ ˆ๋“œ ์ œ์–ด๊ถŒ์€ ๋‹ค๋ฆ„์•„๋‹Œ ์‹œ์Šคํ…œ์—๊ฒŒ ๋„˜๊ฒจ์ง‘๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์‹œ์Šคํ…œ์€ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์ฃ .

์‹œ์Šคํ…œ์€ ์•Œ์•„์„œ suspend ๋˜๊ฑฐ๋‚˜ ์ˆ˜ํ–‰์ด ํ•„์š”ํ•œ ๋‹ค๋ฅธ ์ž‘์—…๋“ค์˜ ์šฐ์„ ์ˆœ์œ„๋“ค์„ ํŒ๋‹จํ•ด๊ฐ€๋ฉฐ ์ฒ˜๋ฆฌํ•ด๋‚˜๊ฐ‘๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ์ด suspend ๋˜์—ˆ๋˜ ํ•จ์ˆ˜์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ด์กŒ๋‹ค๊ณ  ํŒ๋‹จํ•˜๋Š” ์ˆœ๊ฐ„, ์“ฐ๋ ˆ๋“œ ์ œ์–ด๊ถŒ์€ ๋‹ค์‹œ async ํ•จ์ˆ˜์˜€๋˜ data(for: request) ํ•จ์ˆ˜์—๊ฒŒ ์žฌ๊ฐœ(resume)๋˜๊ณ  ์ดํ›„์˜ ์ž‘์—…๋“ค์ด ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ž ๋‹ค์‹œ ๋Œ์•„๊ฐ€์„œ Suspend๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š” ๊ณผ์ •์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณผ๊ฒŒ์š”.

Synchronousํ•œ ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ์˜ ์Šคํƒ ์˜์—ญ์— ํ•จ์ˆ˜๋“ค์ด push ๋˜๋ฉฐ ์Œ“์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ํ•จ์ˆ˜์˜ ์‹คํ–‰์ด ๋๋‚˜๋ฉด pop ๋˜์–ด ์Šคํƒ์—์„œ ์ œ๊ฑฐ๋˜์ฃ .

์•„์ฃผ ๊ฐ„๋‹จ๋ช…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด asynchronousํ•œ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–จ๊นŒ์š”?

async ํ•จ์ˆ˜๋ผ๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ, scope ์ „์ฒด๋ฅผ ํ•œ ๋ฒˆ ๋Œ๋ฉฐ suspension point (await) ๋งˆ๋‹ค ์–ด๋–ค ๋ณ€์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์‚ฌ์šฉ๋˜๋Š”์ง€๋ฅผ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ, id์™€ particle์€ ์“ฐ๋ ˆ๋“œ ์‚ฌ์ด๋ฅผ ์˜ค๊ฐˆ ํ•„์š”๊ฐ€ ์—†๋Š” local ๋ณ€์ˆ˜์ด์ฃ ?

๋”ฐ๋ผ์„œ ํ•ด๋‹น ๋ณ€์ˆ˜๋“ค์€ synchronous ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์Šคํƒ ์˜์—ญ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด await์—์„œ ์‚ฌ์šฉ๋œ newArticles ๋ณ€์ˆ˜*(ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์ˆ˜์ด์ง€๋งŒ ํŽธ์˜์ƒ ๋ณ€์ˆ˜๋ผ๊ณ  ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.)*์˜ ๊ฒฝ์šฐ๋Š” ์–ด๋–จ๊นŒ์š”?

suspend๋˜๋Š” ์ฝ”๋“œ๋Š” ์ž ๊น ๋ฉˆ์ถฐ์žˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ๋ณ€์ˆ˜๋“ค์„ ๋ฉˆ์ถ”๊ธฐ ์ด์ „๊ณผ ์ดํ›„ ๋ชจ๋“  ์‹œ์ ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Swift๋Š” ์ด๋ฅผ ์œ„ํ•ด Heap ์˜์—ญ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

add ํ•จ์ˆ˜๋ฅผ ํž™ ์˜์—ญ์— ์ €์žฅํ•˜๊ณ  ๋‚˜๋ฉด ์Šคํƒ ์˜์—ญ์—๋Š” ํ•ด๋‹น ํ”„๋ ˆ์ž„์„ ๊ณ„์† ๋ถ™์žก๊ณ  ์žˆ์„ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹คํ–‰์ด ํ•„์š”ํ•œ save ํ•จ์ˆ˜๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.

์ด save ํ•จ์ˆ˜ ์•ˆ์— ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ await ์ฝ”๋“œ๊ฐ€ ๋‹ด๊ฒจ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๋ฉด, ํ•ด๋‹น save ํ•จ์ˆ˜ ๋˜ํ•œ ํž™ ์˜์—ญ์œผ๋กœ ์˜ฎ๊ฒจ์ง„ ํ›„ ์‹œ์Šคํ…œ์— ์“ฐ๋ ˆ๋“œ ์ œ์–ด๊ถŒ์„ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์“ฐ๋ ˆ๋“œ๋Š” ๋‹ค๋ฅธ ์ž‘์—…๋“ค(otherWork1, otherWork2)์„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํž™ ์˜์—ญ์— ๋ณด๊ด€ํ•˜๋ฉฐ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํž™ ์˜์—ญ์—๋Š” async ํ•จ์ˆ˜๋“ค์˜ ์Šคํƒ๋“ค์ด ๋ชจ์—ฌ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์ฃ .

Continuation์ด๋ผ๋Š” ๊ฒƒ์ด ์ด๋Ÿฐ ํž™ ์˜์—ญ์˜ async ์Šคํƒ์„ ๋Œ€ํ‘œํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Continuation์ด๋ž€ ๋‹จ์ˆœํžˆ await ์ดํ›„์— ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…๋“ค์„ ํ‘œํ˜„ํ•˜๋Š” ๋ง์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

withCheckedThrowingContinuation(continuation:)๊ณผ ๊ฐ™์€ ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉ๋˜๋‹ˆ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!

์ž‘์—…์ด ์—†๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒ๊ธฐ๊ณ  ํž™ ์˜์—ญ์— ์ €์žฅ๋œ async continuation์ด ๋‹ค์Œ ์ž‘์—…์œผ๋กœ ์„ ํƒ๋˜๋ฉด, ํž™ ์˜์—ญ์— ์žˆ๋˜ ์ž‘์—… ์Šคํƒ์„ ํ•˜๋‚˜์”ฉ ๋‹ค์‹œ ์Šคํƒ ์˜์—ญ์œผ๋กœ ๋ถˆ๋Ÿฌ์™€ ์ฐจ๊ทผ์ฐจ๊ทผ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋•Œ, ์ž‘์—…์ด ์—†๋Š” ์“ฐ๋ ˆ๋“œ๋ผ๋Š” ๊ฒƒ์€ await ์ด์ „์— ์ˆ˜ํ–‰ํ•˜๋˜ ์“ฐ๋ ˆ๋“œ์ผ์ˆ˜๋„ ์žˆ๊ณ  ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด์ฃ .

์ž ๊ทธ๋ž˜์„œ ์ด async / await๋ฅผ ์ด์šฉํ•œ Concurrency๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋ ๊นŒ์š”?

Task

์œ„์˜ ์˜ˆ์‹œ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

์ด ์˜ˆ์‹œ๋Š” ์ƒ๋‹นํžˆ ์ข‹์€ ์˜ˆ์‹œ์ด๊ณ  ์•„์ฃผ ์ •์ƒ์ ์œผ๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ•œ ๊ฐ€์ง€ ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

for in์„ ํ†ตํ•ด์„œ ์—ฌ๋Ÿฌ๋ฒˆ์˜ URLSession์„ awaitํ•˜๋Š” ๊ฒƒ์ธ๋ฐ์š”.. ์ด๋Ÿฐ ์‹์˜ ๊ตฌํ˜„์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๋ฃจํ”„๋งŒ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

asyncํ•˜๊ฒŒ๋Š” ๊ตฌํ˜„ํ•˜์˜€์ง€๋งŒ concurrentํ•˜์ง€๋Š” ๋ชปํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ fetchThumbnails()์ด๋ผ๋Š” ํ•จ์ˆ˜ ๋˜ํ•œ ๊ฒฐ๊ตญ์—๋Š” async ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ์˜ ์–ด๋”˜๊ฐ€์—์„œ๋Š” async ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ด์ค„ ๊ณณ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋•Œ Task๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค.

Task๋Š” concurrentํ•œ ์ฝ”๋“œ ์ˆ˜ํ–‰์„ ์œ„ํ•œ ์ƒˆ๋กœ์šด async ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

async ํ•จ์ˆ˜๋ฅผ ๋‹จ์ˆœํžˆ call ํ•˜๋Š” ๊ฒƒ์€ Task๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค! (GCD ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด call ํ•  ์ˆ˜๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.)

ํ•˜์ง€๋งŒ ์–ด๋–ค Task๋“ค์ด ์žˆ๋‚˜ ๋ณด๊ธฐ ์ด์ „์— Task Tree๋ผ๋Š” ๊ฐœ๋…์„ ์•Œ์•„๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Task Tree

Task Tree๋Š” Task์˜ ์ทจ์†Œ(cancellation), ์šฐ์„ ์ˆœ์œ„(priority), ์ง€์—ญ๋ณ€์ˆ˜(task-local variables) ๋“ฑ์˜ ์†์„ฑ๋“ค์„ ๊ฒฐ์ •ํ•˜๋Š” ์•„์ฃผ ์ค‘์š”ํ•œ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์–ด๋–ค async ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ async ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ๋‘ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ์—๋Š” ๊ฐ™์€ Task๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜ async-let์—์„œ ์‚ฌ์šฉ๋œ ์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ๋ฅผ ๋จผ์ € ํ•œ ๋ฒˆ ๊ฐ€์ ธ์™€๋ดค์Šต๋‹ˆ๋‹ค.

fetchOne() ํ•จ์ˆ˜๊ฐ€ ๋‘ ๊ฐ€์ง€์˜ Task data์™€ metadata๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

fetchOneThumbnail() ํ•จ์ˆ˜๋Š” ๋‘ ๊ฐ€์ง€ Task๋ฅผ child๋กœ ๊ฐ–๊ณ  ์žˆ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ํ•œ Task๊ฐ€ ๋‹ค๋ฅธ Task๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์‹คํ–‰๋œ Task๋“ค์€ ํ˜„์žฌ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” Task์˜ Child Task๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

Task๋Š” ํ•จ์ˆ˜์— ์ข…์†๋œ ๊ฐœ๋…์€ ์•„๋‹ˆ์ง€๋งŒ ํ•จ์ˆ˜์˜ ์ƒ๋ช…์ฃผ๊ธฐ์— ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Parent Task๋Š” ์ข…์†๋œ ๋ชจ๋“  Child Task๋“ค์ด ์ข…๋ฃŒ๋˜๊ธฐ ์ „์—๋Š” ์ข…๋ฃŒ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ metadata Task๊ฐ€ ์—๋Ÿฌ๋ฅผ throwํ•˜๋ฉด์„œ ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค.

๋‘ Task๋Š” ๊ฐ™์€ guard ๋ฌธ ๋‚ด์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฆ‰์‹œ ์—๋Ÿฌ๋ฅผ throwํ•˜๊ณ  ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

ํ•˜์ง€๋งŒ Task์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด โ€œ์ฆ‰์‹œโ€ ์ข…๋ฃŒํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

metadata Task๊ฐ€ ์‹คํŒจํ–ˆ๋”๋ผ๋„ data Task๋Š” ์—ฌ์ „ํžˆ ๋™์ž‘์ค‘์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ•ด๋‹น Task๊ฐ€ ์ทจ์†Œ๋˜์—ˆ๋‹ค๋Š” ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ฃผ๊ณ  Task๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋ชจ๋“  Task๊ฐ€ ์ข…๋ฃŒ๋œ ์‹œ์ ์— ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ทจ์†Œ๋˜์—ˆ๋‹ค(cancelled) ๋ผ๋Š” ๊ฒƒ์€ ํ•ด๋‹น Task๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ๋” ์ด์ƒ ํ•„์š”์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค„ ๋ฟ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ทจ์†Œ๋œ Task๊ฐ€ Child Task๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๋ชจ๋“  Child Task๋“ค ๋˜ํ•œ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ Task Tree ๋™์ž‘์€ ARC์™€ ๊ฐ™์ด ์‹ค์ˆ˜๋กœ ๋ฒŒ์–ด์ง€๋Š” Task Leak๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•จ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ Task Tree์˜ ํŠน์„ฑ์„ ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Task์˜ ์ทจ์†Œ๋Š” ํ˜‘๋ ฅ์ (cooperative) ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

  1. Task๋Š” ์ทจ์†Œ๋˜๋”๋ผ๋„ ์ฆ‰์‹œ ์ข…๋ฃŒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. Task์˜ ์ทจ์†Œ ์—ฌ๋ถ€๋Š” ์–ด๋””์—์„œ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. (synchronousํ•œ ์ฝ”๋“œ์—์„œ๋„)

์ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ Task๊ฐ€ ์ทจ์†Œ๋˜์—ˆ์„ ๋•Œ์˜ ๋™์ž‘์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด๋ผ๊ณ  ํ•˜๋„ค์š”.

์ด ๋ง์€ Task๊ฐ€ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๋™์ž‘์ผ์ˆ˜๋ก ์ทจ์†Œ์— ๋Œ€์‘ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๊ผญ ํ•„์š”ํ•˜๋‹ค๋ผ๋Š” ๋œป ๊ฐ™์Šต๋‹ˆ๋‹ค.

์„ค๋ช…๋งŒ์œผ๋กœ๋Š” ๋ฌด์Šจ ๋ง์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์œผ๋‹ˆ ์˜ˆ์‹œ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์™€๋ณด์ฃ !

์œ„์™€ ๊ฐ™์ด concurrentํ•œ ๋™์ž‘์ด ์ˆ˜ํ–‰๋˜๊ธฐ ์ „์— Task.checkCancellation()๋‚˜ if Task.isCancelled { break }์„ ํ†ตํ•ด ๋ถˆํ•„์š”ํ•œ ์ธ๋„ค์ผ ์ƒ์„ฑ์˜ ๋™์ž‘์„ ๋ฐฉ์ง€ํ•˜๊ณ  ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„ ์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ Task๊ฐ€ ์ทจ์†Œ๋˜์—ˆ๋”๋ผ๋„ thumbnails์—๋Š” ์ทจ์†Œ๋˜๊ธฐ ์ด์ „์— ์„ฑ๊ณตํ•œ ๋ฐ์ดํ„ฐ๋“ค์ด ๋‹ด๊ฒจ์žˆ๊ณ , ๊ทธ ๋ฐ์ดํ„ฐ๋“ค์ด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋นˆ ๋ฐ์ดํ„ฐ ๋“ฑ์˜ ๊ฒฐ๊ณผ๋Š” UI์— ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ผ๋‘์— ๋‘๊ณ  ์ž‘์—…ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์šฐ๋ฆฌ๋Š” Task๊ฐ€ ์–ธ์ œ ์ทจ์†Œ๋˜๊ฑฐ๋‚˜ ์™„๋ฃŒ๋˜๋Š”์ง€๋ฅผ ์•Œ์•˜์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Ž

๋“œ๋””์–ด Swift๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ Task๋ฅผ ์•Œ์•„๋ณผ ๋•Œ๊ฐ€ ๋˜์—ˆ๋„ค์š”. ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด์ฃ !

Structured Tasks

  • async-let Tasks

์ง€๊ธˆ๊นŒ์ง€์˜ URLSession.data() ํ•จ์ˆ˜๋Š” ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ™”์‚ดํ‘œ์˜ ๋ฐฉํ–ฅ๋Œ€๋กœ ๋‹จ ํ•œ๊ฐ€์ง€์˜ ํ๋ฆ„(๋‹จ๋ฐฉํ–ฅ)๋งŒ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” URLSession์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜ํ–‰ ์‹œ๊ฐ„๋™์•ˆ ๋‹ค๋ฅธ ์ž‘์—…๋“ค์ด ์ˆ˜ํ–‰๋˜๊ธธ ์›ํ•ฉ๋‹ˆ๋‹ค.

async-let์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ„์ฒ˜๋Ÿผ ํ๋ฆ„์ด ๋‘ ๊ฐ€์ง€๋กœ ๋‚˜๋‰˜์–ด์ง‘๋‹ˆ๋‹ค.

Child Task๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , URLSession.data() ํ•จ์ˆ˜๋ฅผ asyncํ•˜๊ฒŒ ์‹คํ–‰ํ•จ๊ณผ ๋™์‹œ์— result์—๋Š” ์ž„์‹œ ๊ฐ’(placeholder) ์„ ๋„˜๊ฒจ์ค€์ฑ„๋กœ await ํ‚ค์›Œ๋“œ๊ฐ€ ๋“ฑ์žฅํ•  ๋•Œ๊นŒ์ง€ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

await์—์„œ ๊ธฐ๋‹ค๋ฆฌ๋˜ ์ž‘์—…์€ async ํ•จ์ˆ˜๊ฐ€ ๋์ด ๋‚˜๋ฉด result ๊ฐ’์„ ๋Œ€์ฒดํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์œ„ ์ฝ”๋“œ๋ฅผ async-let์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๊พธ๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”?

try await์€ child task์—๊ฒŒ ์ž‘์—…์„ ๋„˜๊ฒจ์คฌ๊ธฐ ๋–„๋ฌธ์— ๋” ์ด์ƒ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ง€์ ์—์„œ๋Š” ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Parent task์—์„œ ๊ฒฐ๊ณผ๋กœ ๋‚˜์˜จ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•„์š”ํ•˜์ฃ .

๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ”์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ๊ฐ์˜ URLSession์—์„œ try await์„ ์ œ๊ฑฐํ•˜๋Š” ๋Œ€์‹  ๋งจ ์•ž์— async๋ฅผ ๋ถ™์—ฌ์ฃผ๊ณ ,

Parent task์ธ fetchOneThumbnail() ํ•จ์ˆ˜์—์„œ data์™€ metadata๊ฐ€ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— try await ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค!

  • Group Tasks

async-let์€ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” Task์˜ ๊ฐœ์ˆ˜๊ฐ€ ์ •ํ•ด์ ธ์žˆ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ ์œ„ ์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ๋ฅผ ๋ณด๋ฉด, ๋ช‡ ๊ฐœ์˜ ์ธ๋„ค์ผ์„ ์ƒ์„ฑํ•˜๋˜์ง€ ๊ฐ„์— fetchOne์ด๋ผ๋Š” Task๋Š” ๊ณ ์ •์ ์œผ๋กœ ๋‘ ๊ฐœ์˜ Child Task๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ id์˜ ๊ฐœ์ˆ˜์— ๋”ฐ๋ผ์„œ๋Š” ์ˆ˜ํ–‰ํ•  fetchOne() ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  Task์˜ ๊ฐœ์ˆ˜๋Š” ๋‹ฌ๋ผ์ง€๊ฒ ์ฃ ?

Task Group์€ ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Task Group์€ ๋™์  ๊ฐœ์ˆ˜์˜ Task์˜ ์ˆ˜ํ–‰์ด ๋™์‹œ์— ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๊ธฐ ์œ„ํ•ด ๊ณ ์•ˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

withThrowingTaskGroup(of:) ๋ฅผ ํ†ตํ•ด์„œ Task Group์„ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํ•จ์ˆ˜๋Š” Child Task๋ฅผ ์ƒ์„ฑํ•˜๋Š” group ์ด๋ผ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Context๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ for ๋ฃจํ”„์˜ ๊ฐ ๋ฃจํ”„๋“ค์€ group.async๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋žœ๋คํ•œ ์‹œ๊ธฐ์— ์ˆœ์„œ ์ƒ๊ด€ ์—†์ด ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

group ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฃจํ”„๋ฅผ ์ „๋ถ€ ๋Œ์•˜๋”๋ผ๋„ Task Tree์˜ ํŠน์„ฑ์— ์˜ํ•ด ๋ชจ๋“  Task๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ await๋œ๋‹ค๋Š” ๊ฒƒ๋„ ์•Œ ์ˆ˜ ์žˆ๊ฒ ์ฃ !

๊ทธ๋Ÿฐ๋ฐ.. ๋ชจ๋“ ๊ฒŒ ํ‰ํ™”๋กœ์›Œ ๋ณด์ด๋Š” ์œ„ ์ฝ”๋“œ๋Š” ๋†€๋ž๊ฒŒ๋„ ์‹ฌ๊ฐํ•œ ์—๋Ÿฌ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.. ๐Ÿ˜ฐ

์‹ฌ์ง€์–ด ๋นŒ๋“œ๋„ ์•ˆ๋˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ์—๋Ÿฌ๋ฅผ ๋‚ด๋ฟœ์ฃ ..

๋ฐ”๋กœ Data Race Issue๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค..

Data Race Issue๋Š” ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ Task์—์„œ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์—ฐ์‚ฐ๋งŒ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์—ฌ๋Ÿฌ Task์—์„œ ๋™์‹œ์— ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ํฌ๋Ÿฌ์‰ฌ๊ฐ€ ๋‚˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค..

์ด ๊ฒฝ์šฐ์—๋Š” ํ•˜๋‚˜์˜ thumbnails ๋”•์…”๋„ˆ๋ฆฌ์— ์—ฌ๋Ÿฌ Task๋“ค์ด ๋™์‹œ์— ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๊ณ  ์žˆ์ฃ ?

์ด๋Š” Concurrency ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ๋•Œ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ”ํžˆ ํ•˜๋Š” ์‹ค์ˆ˜ ์ค‘์— ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Data Race Issue์˜ ํ•ด๊ฒฐ์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋‹ฌ๋ ค์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—…๋ฐ์ดํŠธ๋œ Swift Concurrency๋Š” ์ด๋ฅผ ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ๋ฏธ๋ฆฌ ๋ฐœ๊ฒฌํ•˜์—ฌ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์ด์ฃ ! ๐Ÿ‘ (์ด๋ ‡๊ฒŒ ๋“ค์œผ๋‹ˆ๊นŒ ๋ฉ‹์ง€์ฃ ?)

๊ทธ๋ž˜์„œ ์—๋Ÿฌ๋ฅผ ์žก์•„์ฃผ๊ธด ํ•˜๋Š”๋ฐ ํ•ด๊ฒฐ์€ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”?

Task๋Š” ์‚ฌ์‹ค @Sendable ํด๋กœ์ €๋ผ๋Š” ํด๋กœ์ €์— ์˜ํ•ด ๊ฐ์‹ธ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

@Sendable ํด๋กœ์ €์˜ ์บก์ฒ˜๋Š” ๋…ํŠนํ•˜๊ฒŒ๋„ mutable ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์บก์ฒ˜ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ค ๊ฐ’๋“ค์„ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€ ํ•˜๋ฉด?

๊ฐ’ ํƒ€์ž…(Int, String, โ€ฆ) ๋ณ€์ˆ˜, actors, ๊ณ ์œ ํ•œ synchronization์„ ๊ฐ€์ง„ class ๋ฅผ ์บก์ฒ˜ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ์˜ˆ์‹œ๋กœ ๋Œ์•„๊ฐ€์„œ ์—๋Ÿฌ๋ฅผ ๊ณ ์ณ๋ณผ๊ฒŒ์š”..

thumbnails์— ์ง์ ‘์ ์œผ๋กœ ๊ฐ’์„ ๋Œ€์ž…ํ•˜๋Š” ๋Œ€์‹ , String ํƒ€์ž…๊ณผ UIImage ํƒ€์ž…์˜ ํŠœํ”Œ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ํ›„์— for await ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฐ’๋“ค์„ thumbnails์— ๋Œ€์ž…ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

AsyncSequence ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ๊ฐ’์„ ๋‹ค๋ฃจ๊ณ  ์žˆ๋‹ค๋ฉด for await ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•ด๋ณผ ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ๋„ค์š”.

์ž.. ์—ฌ๊ธฐ๊นŒ์ง€ ์•Œ์•„๋ณธ async-let ๊ณผ Grouped Tasks๋Š” Structured Task๋ผ๋Š” ๊ฐ์ž์˜ hierarchy๊ฐ€ ์ •๋ˆ๋œ Task๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด์˜€์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์–ธ์ œ๋‚˜ ์ •๋ˆ๋œ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— Swift๋Š” Unstructured Tasks๋ผ๋Š” API๋ฅผ ์ถ”๊ฐ€๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Unstructured Tasks

Hierarchy๊ฐ€ ์ •๋ˆ๋˜์ง€ ์•Š์€ Task์—๋Š” ์–ด๋–ค Task๋“ค์ด ์žˆ์„๊นŒ์š”?

๋จผ์ €, Parent Task๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. asyncํ•˜์ง€ ์•Š์€ ์ปจํ…์ŠคํŠธ์—์„œ asyncํ•œ Task๋ฅผ ์‹œ์ž‘ํ•ด์•ผํ•  ๋•Œ๊ฐ€ ์ด๋Ÿฐ ๊ฒฝ์šฐ์ฃ .

๋˜ Task๊ฐ€ ํ•˜๋‚˜์˜ scope๋ฅผ ๋„˜์–ด ์—ฌ๋Ÿฌ scope์—์„œ ์ด๋ฃจ์–ด์ง€๋„๋ก ํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ๋„ ์žˆ์„๊ฒ๋‹ˆ๋‹ค.

๋ณดํ†ต delegate ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ๋•Œ ํ”ํžˆ ์ผ์–ด๋‚˜๋Š” ์ผ์ด๋ผ๊ณ  ํ•˜๋„ค์š”.

์œ„ ์˜ˆ์‹œ๋ฅผ ๋ด…์‹œ๋‹ค..

delegate ํ•จ์ˆ˜์ธ collectionView(willDisplay:, forItemAt) ํ•จ์ˆ˜๋Š” UI ๋ ˆ์ด์–ด์˜ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— asyncํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” fetchThumbnails() ํ•จ์ˆ˜๋Š” async ํ•จ์ˆ˜์ด์ฃ .

์ด๋Ÿด ๋•Œ๊ฐ€ ๋ฐ”๋กœ Unstructured Task๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์ž…๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ async ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์€ Task๋กœ ๊ฐ์‹ธ์ค๋‹ˆ๋‹ค.

๋Ÿฐํƒ€์ž„๋™์•ˆ ์ด Task๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์„ ๋งˆ์ฃผ์น˜๊ฒŒ ๋˜๋ฉด, ์ˆ˜ํ–‰ํ•˜๋Š” scope์™€ ๊ฐ™์€ actor์—์„œ ์‹คํ–‰๋˜๋„๋ก ์˜ˆ์•ฝ์„ ํ•ด๋‘ก๋‹ˆ๋‹ค.

์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ์—๋Š” MainActor์—์„œ ์‹คํ–‰์ด ๋  ๊ฒ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ„ํŽธํ•˜๋‹ค๋ฉด ๋‹จ์ ๋„ ๋‹น์—ฐํžˆ ์žˆ๊ฒ ์ฃ ?

Task์˜ ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ scope์— ์ข…์†๋˜์ง€ ์•Š๊ณ  synchronousํ•œ ์ฝ”๋“œ ์ค‘๊ฐ„์—์„œ๋„ ํ˜ธ์ถœ์ด ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Structured Task์—์„œ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ์—ˆ๋˜ ์ทจ์†Œ์™€ await๋ฅผ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ, Task๋ฅผ ์ƒ์„ฑํ•œ ๋’ค์— thumbnailTasks๋ผ๋Š” ๋”•์…”๋„ˆ๋ฆฌ์— ์ €์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๋‚˜์ค‘์—๋„ ์–ธ์ œ๋“ ์ง€ ์ ‘๊ทผํ•ด์„œ ์ž‘์—…์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

defer๋ฌธ์„ ์‚ฌ์šฉํ•ด Task๊ฐ€ ๋๋‚œ ์‹œ์ ์— ์ €์žฅ๋œ Task๋ฅผ ํ•ด์ œํ•จ์œผ๋กœ์จ ์ด๋ฏธ ์™„๋ฃŒ๋œ Task๋ฅผ ์ทจ์†Œํ•˜๋Š” ์ผ๋„ ๋ฐฉ์ง€ํ•ด๋‘” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋„ค์š”.

๐Ÿ™‹ ์–ด๋ผ ๊ทธ๋Ÿฐ๋ฐ.. ๊ฐ™์€ ๋ฐ์ดํ„ฐ์— ์—ฌ๋Ÿฌ Task๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋ฉด ์•ˆ๋œ๋‹ค๊ณ  ํ•˜์ง€ ์•Š์•˜๋‚˜์š”?

๋งž์Šต๋‹ˆ๋‹ค.. ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ์—๋Š” @MainActor, ์ฆ‰ ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ ˆ๋Œ€๋กœ ๋™์‹œ์— ์ผ์–ด๋‚  ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.

์…€์ด ํ™”๋ฉด์—์„œ ๋ฒ—์–ด๋‚˜๋ฉด ์ž‘์—…์„ ์ทจ์†Œํ•ด๋„ ๋˜๊ฒ ์ฃ .

๋‹ค์Œ๊ณผ ๊ฐ™์ด task.cancel() ๋กœ Task๋ฅผ ์ทจ์†Œํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Detached Tasks

์–ด๋ผ ๋ญ๊ฐ€ ํ•˜๋‚˜ ๋˜ ์žˆ์ฃ โ€ฆ?

Unstructured Tasks๋Š” ์–ด๋–ค ์Šค์ฝ”ํ”„์—์„œ๋„ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋Š” Task์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์–ด๋–ค ์ปจํ…์ŠคํŠธ์—์„œ ์‹œ์ž‘๋˜์—ˆ๋Š”์ง€๋Š” ์ค‘์š”ํ•œ ์š”์†Œ์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น scope์˜ ๋ณ€์ˆ˜๋„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ ,

Detached Tasks๋Š” ๊ทธ ์–ด๋–ค ๊ฒƒ๋„ ์ƒ๊ด€์ด ์—†์„ ๋–„ ์‚ฌ์šฉํ•˜๋Š” Task์ž…๋‹ˆ๋‹ค.

Detached Tasks๋Š” ์ปจํ…์ŠคํŠธ๋กœ๋ถ€ํ„ฐ ๋…๋ฆฝ์ ์ž…๋‹ˆ๋‹ค.

์‹œ์ž‘๋œ scope์—์„œ ์•„๋ฌด ๊ฐ’๋„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ฌ์ง€์–ด ๊ฐ™์€ actor์—์„œ ์‹คํ–‰๋˜๋„๋ก ๋˜์–ด์žˆ์ง€๋„ ์•Š์•„์„œ ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

์œ„ ์˜ˆ์‹œ๋Š” ์ธ๋„ค์ผ์„ ์ƒ์„ฑํ•œ ํ›„์— ๋กœ์ปฌ ๋””์Šคํฌ์— ์บ์‹ฑ์„ ํ•˜๋Š” ์ž‘์—…์„ Detached Task์—์„œ ์ž‘์—…ํ•˜๋„๋ก ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์บ์‹ฑ์€ @MainActor์—์„œ ์ฒ˜๋ฆฌ๋  ํ•„์š”๊ฐ€ ์ „ํ˜€ ์—†์ฃ .

๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์งˆ ํ•„์š”๋„ ์—†์Šต๋‹ˆ๋‹ค.

Task.detached(priority:) ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ปจํ…์ŠคํŠธ์—์„œ ๋…๋ฆฝ๋œ Detached Task๋ฅผ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Detached Task์— Task Group์„ ์‚ฌ์šฉํ•ด์„œ hierarchy๋ฅผ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด ํ•„์š”ํ•˜์ง€๋งŒ ์—ฐ๊ฒฐ๋œ ์ž‘์—…์ด ํ•„์š”ํ•  ๋•Œ ์•„์ฃผ ์œ ์šฉํ•˜๊ฒ ์ฃ !

์ •๋ฆฌ

Actor

๋๋‚œ ์ค„ ์•Œ์•˜์ฃ ..?

ํ•˜์ง€๋งŒ ์•„์ง ๋งŽ์ด ๋‚จ์•˜์Šต๋‹ˆ๋‹ค. ๐Ÿคฏ

์œ„์—์„œ Actor๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ์—ˆ์ฃ ..?

์ด๊ฒŒ ๋ญ”์ง€๋„ ์•Œ์•„๋ด์•ผ์ฃ ..

Actor๊ฐ€ ๋ญ”์ง€ ์•Œ์•„๋ณด๋ ค๋ฉด ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด๋ฏธ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณธ Data Race Issue์™€ ๊ด€๋ จ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์‹œ์ž‘ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

Data Race๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ Task์—์„œ ๋™์‹œ์— ํ•˜๋‚˜์˜ mutable ๊ฐ’์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ์š”?

๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ Task์— ๊ฑธ์ณ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋ฉด ํ•ด๊ฒฐ๋˜๊ฒ ์ฃ ?

๊ทธ๋Ÿฌ๋ฉด ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋˜๊ฒ ๋„ค์š”!

let์œผ๋กœ ๊ฐ’์ด ๊ณ ์ •๋œ ๊ฐ’์„ ๊ฐ Task์—์„œ mutableํ•œ ๊ฐ’์œผ๋กœ ๋ณต์‚ฌํ•œ ๋’ค ์ž‘์—…์„ ํ•ด์ฃผ๋ฉด ๋˜๊ฒ ์ฃ .

์•„๋‡จ ์•ˆ๋์Šต๋‹ˆ๋‹ค. ๐Ÿ™…โ€โ™‚๏ธ

์—๋Ÿฌ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ Task๋งˆ๋‹ค ๋ณต์‚ฌ๋œ ๊ฐ’์€ ์„œ๋กœ์˜ ๊ฐ’์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ๋ชปํ•˜๊ฑฐ๋“ ์š”.

๊ทธ๋Ÿฌ๋ฉด ์ด๋ ‡๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ๊ฐ Task๋“ค์ด ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” mutable Task๊ฐ€ ํ•„์š”ํ•˜๋‹ค!

Swift๋Š” ์ด๋ฏธ ๊ทธ๋Ÿฐ feature๋“ค์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๋Š” ์˜ค๋ž˜๋œ ๋ฌธ์ œ๊ฑฐ๋“ ์š”..

mutable state๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ์ž‘์—…์€ ๋กœ์šฐ๋ ˆ๋ฒจ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Atomics, Locks, ๋” ๋†’์€ ๋ ˆ๋ฒจ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Serial DIspatch Queues๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋“ค์€ ๋ชจ๋‘ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜๊ณ  ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Shared mutable state์— Data Race ์—†์ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ๋ฒ•์ด ์กฐ๊ธˆ์ด๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด ๋ฐ”๋กœ ์•ฑ์ด ํฌ๋Ÿฌ์‰ฌ๋œ๋‹ค๋Š” ๊ฒƒ์ด์ฃ .

Actors๋Š” ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  shared mutable state์˜ ๋™๊ธฐํ™”๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ์ด๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

Actors๋Š” state๋ฅผ ๋‹ค๋ฅธ ๋ชจ๋“  ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น state์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ๋ฌด์กฐ๊ฑด actor ๋‚ด๋ถ€์— ๋“ค์–ด๊ฐ€์•ผ๋งŒ ํ•˜์ฃ .

Actor๋Š” ์กฐ๊ธˆ ํŠน์ดํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ํƒ€์ž…์ด๊ฑฐ๋“ ์š”.

๋งˆ์น˜ struct, enum, class์™€ ๊ฐ™์ด ํ”„๋กœํผํ‹ฐ, ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž ๋“ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

protocol๊ณผ extension ๋˜ํ•œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜, actor๋Š” shared mutable state์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๋งŒํผ class์™€ ๊ฐ™์€ ์ฐธ์กฐ ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•์€ class์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์ฃผ์˜ํ•  ์ ์ด ์žˆ๋‹ค๋ฉด class์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ƒ์†์„ ์ง€์›ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค!

๊ทธ๋ฆฌ๊ณ  ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ ์€ actor์—์„œ ์ •์˜๋œ ๊ฐ’๋“ค์€ ๋™์‹œ์— ์ ‘๊ทผ๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅ๋˜์–ด ์žˆ๋‹ค~๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ์— ์ ์šฉํ•ด๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ฐ™์€ ๊ฐ’์— ์ ‘๊ทผํ•˜์ง€๋งŒ, ์ ˆ๋Œ€ ๋™์‹œ์— ์ ‘๊ทผํ•  ์ˆ˜๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ˆœ์„œ๋Œ€๋กœ 2, 1์ด๋‚˜ 1, 2๊ฐ€ ์ถœ๋ ฅ๋ ๊ฒ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ suspend๋œ ์ž‘์—…์ด actor ์•ˆ์—์„œ ์–Œ์ „ํžˆ ์ฐจ๋ก€๋ฅผ ๊ธฐ๋‹ค๋ฆด ๊ฒƒ์ด๋ผ๋Š” ๋ณด์žฅ์€ ๋˜๋Š” ๊ฑธ๊นŒ์š”?

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ๊ทธ๋Ÿฐ ์—ญํ• ์„ ํ•˜๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

actor์˜ ์™ธ๋ถ€์—์„œ๋Š” await ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์ž‘์—…์ด suspendableํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ actor์˜ ๋‚ด๋ถ€์—์„œ๋Š” ์ด์™€ ๊ฐ™์€ ํ‚ค์›Œ๋“œ๋Š” ํ•„์š”๊ฐ€ ์—†์ฃ .

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

Actor Reentrancy

์œ„ ์ฝ”๋“œ๋Š” ์ด๋ฏธ์ง€๋ฅผ ์บ์‹ฑํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” actor์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” await์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ๊ณผ์ •์€ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ์†Œ์š”๋˜๋Š” ์ž‘์—…์ด๋‹ˆ await์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋™์‹œ์— ๋‘ ๊ตฐ๋ฐ์—์„œ ๊ฐ™์€ url์˜ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์˜ค๊ธธ ์›ํ•˜๊ณ , ํ•˜๋‚˜์˜ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜๋Š” ๋™์•ˆ ์„œ๋ฒ„์˜ ์ด๋ฏธ์ง€๊ฐ€ ๊ต์ฒด๋˜๋Š” ์ƒํ™ฉ์ด ์žˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

๋‘ ์ž‘์—…์€ ๋™์‹œ์— ์š”์ฒญ๋์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์˜ค๊ฒŒ ๋ ๊ฒ๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ์—๋Š”, ์ด๋ฏธ url์— ํ•ด๋‹นํ•˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉํ•˜๊ณ , ์—†๋‹ค๋ฉด ์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€๋ฅผ ๋„ฃ๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์ด actor ๋‚ด๋ถ€์—์„œ await์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ˆจ๊ฒจ์ง„ ๋ฒ„๊ทธ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ณผ์ •์„ actor์— ์žฌ์ง„์ž…ํ•˜์—ฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๊ณ  ํ•ด์„œ Actor Reentrancy๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๋‹ค์Œ ์„ธ ๊ฐ€์ง€๋ฅผ ํ•ญ์ƒ ์ƒ๊ฐํ•ด๊ฐ€๋ฉฐ ์ฝ”๋“œ๋ฅผ ์งœ๋ด…์‹œ๋‹ค.

  1. ๋˜๋„๋ก synchronousํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ mutate ์‹œํ‚จ๋‹ค.
  2. await์—์„œ suspend๋œ ๋™์•ˆ state๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์Œ์„ ์ƒ๊ฐํ•œ๋‹ค.
  3. await ํ›„์— ์กฐ๊ฑด๋ฌธ ๋“ฑ์„ ํ†ตํ•ด state๊ฐ€ ์˜ˆ์ƒ๋ฒ”์œ„ ์•ˆ์ธ์ง€ ์ฒดํฌํ•œ๋‹ค.

Actor Isolation

Actor๋Š” ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ๋“ค๊ณผ ๋…๋ฆฝ์ ์œผ๋กœ ์žˆ๋Š” ์กด์žฌ๋ผ๊ณ  ํ–ˆ์—ˆ์ฃ ?

๋”ฐ๋ผ์„œ ์™ธ๋ถ€์—์„œ actor์— ์ ‘๊ทผํ•  ๋–„๋Š” ์ด๋Ÿฐ ๋…๋ฆฝ์„ฑ์„ ํ•ด์น˜๋ฉด์„œ ์ ‘๊ทผํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ์กฐ๊ธˆ ์•„๋“ํ•ด์ง‘๋‹ˆ๋‹ค.. ์ฃผ์˜ํ•˜์„ธ์š”โ€ฆ ๐Ÿซ 

  • Protocol

์ด ๊ฒฝ์šฐ Equatable ๋ฉ”์„œ๋“œ๋Š” static ์ด๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ๋‘ actor ํƒ€์ž… ๊ฐ’์˜ ์™ธ๋ถ€์— ์žˆ์œผ๋‹ˆ๊นŒ ๊ฐ€๋Šฅํ•œ ๋ฌธ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด ์ด ๊ฒฝ์šฐ์—๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

hash(into:) ํ•จ์ˆ˜๋Š” actor ๋‚ด๋ถ€์— ๋“ค์–ด๊ฐ€๊ณ , asyncํ•˜์ง€๋„ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด์ƒํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜•

actor ๋‚ด๋ถ€์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์€ ๋งž์ง€๋งŒ, ์‹ค์ œ๋กœ actor๊ฐ€ ๊ฐ–๊ณ ์žˆ๋Š” ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ฑฐ๋“ ์š”..

๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” nonisolated ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋์ด ์•„๋‹™๋‹ˆ๋‹ค..

์ด ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•˜๋Š” actor์˜ ํ”„๋กœํผํ‹ฐ idNumber๊ฐ€ immutableํ•œ ๊ฐ’์ด๊ฑฐ๋“ ์š”.

ํ•˜์ง€๋งŒ mutableํ•œ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋ฉดโ€ฆ?

์–ด๊น€์—†์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์™ธ๋ถ€์—์„œ mutableํ•œ ๊ฐ’์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ Data Race๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”.

  • Closure

์ด๋ฒˆ์—๋Š” ํด๋กœ์ € ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

์œ„ ์˜ˆ์‹œ๋Š” ์•„๋ฌด ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋…๋ฆฝ๋œ ๊ณต๊ฐ„์— ์žˆ๋Š” read() ํ•จ์ˆ˜ ์•ˆ์— ์žˆ๋Š” (๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋…๋ฆฝ๋œ ๊ณต๊ฐ„์— ์žˆ๋Š”) readSome() ํ•จ์ˆ˜๊ฐ€ synchronousํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ !

๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๊ฒฝ์šฐ๋Š” ์–ด๋–จ๊นŒ์š”..

Detached Task์— read() ํ•จ์ˆ˜๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฒฝ์šฐ์—๋Š” ํด๋กœ์ € ์•ˆ์˜ ์ž‘์—…๋“ค์ด ๋…๋ฆฝ๋œ ๊ณต๊ฐ„์— ์žˆ์ง€ ์•Š๊ณ  ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋•Œ๋ฌธ์— ํ•ด๋‹น ํด๋กœ์ €๋Š” actor์— ์žˆ์ง€ ์•Š๊ณ , await ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž ์ด ๊ฒฝ์šฐ๋ฅผ ๋ด…์‹œ๋‹ค..

Book์ด๋ผ๋Š” ์ธ์Šคํ„ด์Šค๋Š” class ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ์ฐธ์กฐ ํƒ€์ž…์ด๋‹ˆ๊นŒ actor ์•ˆ์— ์žˆ์ง€ ๋ชปํ•˜๊ณ  ์™ธ๋ถ€์— ์œ„์น˜ํ•ด์žˆ์ฃ .

actor ์•ˆ์— ์ฐธ์กฐ ํƒ€์ž…์˜ ๊ฐ’์ด ์žˆ๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์•„๋ฌด ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ํ•ด๋‹น ๊ฐ’์— ์ ‘๊ทผ์„ ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๊ฒ ์ฃ ? (Data Race)

์—ฌ๊ธฐ์„œ ์ต์ˆ™ํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค.

Sendable

Sendable ํƒ€์ž…์€ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ actor๋“ค ์‚ฌ์ด์—์„œ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

์–ด๋–ค ๊ฐ’์„ ๊ฐ์ž์˜ actor๋กœ ๋ณต์‚ฌํ•˜๊ณ , ๋ณต์‚ฌ๋œ ๊ฐ’์„ ๋…๋ฆฝ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ๊ฐ’์€ Sendableํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ’ ํƒ€์ž…๊ณผ Actor ํƒ€์ž…์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Sendableํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํด๋ž˜์Šค(์ฐธ์กฐ ํƒ€์ž…) ์˜ ๊ฒฝ์šฐ์—๋Š” ๊ณ ๋ คํ•ด์•ผํ•  ์‚ฌํ•ญ์ด ์žˆ์ฃ ..

  1. ํด๋ž˜์Šค์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ’๋“ค์ด immutable(let) ํ•œ ๊ฒฝ์šฐ
  2. ํด๋ž˜์Šค ๋‚ด๋ถ€์ ์œผ๋กœ ๋™๊ธฐํ™”(NSLock, ...)๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ

ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ํด๋ž˜์Šค๋Š” ๊ทธ๋ ‡์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Sendable์ด ์•„๋‹ˆ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” Sendableํ•˜์ง€ ์•Š์ง€๋งŒ @Sendable ํ•จ์ˆ˜์™€ ๊ฐ™์€ ์ƒˆ๋กœ์šด ํƒ€์ž…์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Sendableํ•ฉ๋‹ˆ๋‹ค.

Sendable์€.. ์˜ˆ์ƒํ•˜์…จ๊ฒ ์ง€๋งŒ ์‚ฌ์‹ค ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค.

Swift์—์„œ concurrentํ•œ ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Sendable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ ๊ฐ’๋“ค์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ๊ฒƒ์ด์ฃ ..!

์ž.. ๋‹ค์‹œ ํด๋กœ์ €๋กœ ๋Œ์•„๊ฐ€๋ด…์‹œ๋‹ค.

ํด๋กœ์ €๊ฐ€ Sendableํ•˜๋ ค๋ฉด ์–ด๋–ค ๊ฒฝ์šฐ์—ฌ์•ผ ํ• ๊นŒ์š”?

๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ํด๋กœ์ €๊ฐ€ ์บก์ฒ˜ํ•˜๋Š” ๋ชจ๋“  ๊ฐ’๋“ค์ด Sendableํ•ด์•ผํ•˜์ฃ .

๋˜ ์บก์ฒ˜ํ•œ ๊ฐ’๋“ค์ด mutable(var) ํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด Data Race๊ฐ€ ๋ฐœ์ƒํ• ํ…Œ๋‹ˆ๊นŒ์š”..

๋งˆ์ง€๋ง‰์œผ๋กœ ํด๋กœ์ €๊ฐ€ synchronousํ•œ ๊ฒฝ์šฐ์— actor์—์„œ ๋…๋ฆฝ๋œ ํ˜•ํƒœ์ด๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์™ธ๋ถ€์—์„œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์ง€๋‹ˆ๊นŒ์š”!

Main Actor

๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ดํŽด๋ณผ ๊ฒŒ ์žˆ์Šต๋‹ˆ๋‹ค.

Main Actor๋ผ๋Š” ํŠน์ˆ˜ํ•œ actor์ธ๋ฐ์š”, ์ด๋ฏธ ์ „์— ํ•œ ๋ฒˆ ์–ธ๊ธ‰๋œ ์ ์ด ์žˆ์—ˆ์ฃ ?

๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ž‘์—…์„ ํ•˜๋‹ค๊ฐ€ ๋‹ค์‹œ ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ๋กœ ๋„˜์–ด์™€ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ..

์•„์ฃผ ์ต์ˆ™ํ•˜์ฃ ?

DispatchQueue.main.async {
  updateButton()
}

๋ณดํ†ต ์œ„์™€ ๊ฐ™์ด DispatchQueue.main์„ ์‚ฌ์šฉํ•ด์˜ค๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค.

@MainActor๋Š” ํ•ด๋‹น ์ž‘์—…์ด ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•˜๋Š” ํ‚ค์›Œ๋“œ์ž…๋‹ˆ๋‹ค.

DispatchQueue.main ๋Œ€์‹  ์‚ฌ์šฉํ•˜์—ฌ ๋ช…์‹œ์ ์œผ๋กœ ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์ค์‹œ๋‹ค..!

References

WWDC21 - Swift concurrency: Behind the Scenes

WWDC21 - Explore structured concurrency in Swift

WWDC21 - Protect mutable state with Swift actors

naljin - Swift async / await & concurrency