์๋ ํ์ธ์, ๊ฐ์์ ๋๋ค. ์ค๋์ 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 ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋ฉ์๋ ๋ชจ๋ ๋น๋๊ธฐ๋ก ๋ง๋ค๋ฉด, ์์ ์ฝ๋๊ฐ ์ฌ์ง์ด ์ค๋น๋ ๋๊ฐ์ง ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋๋จธ์ง ์ฝ๋๊ฐ ๊ณ์ ์คํ๋ ์ ์๋ค.
์ ์ฝ๋์ ๋์์ฑ์ ์ดํดํ๊ธฐ ์ํ ์คํ ์์๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ ์ฝ๋๋ ์ฒซ ๋ฒ์งธ ์ค์์ ์คํ์ ์์ํ๊ณ , ์ฒซ ๋ฒ์งธ await ๊น์ง ์คํ๋๋ค. ์ฆ listPhotos(inGallery: ) ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ , ํด๋น ๋ฉ์๋๊ฐ ๋ฐํ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์คํ์ ์ผ์์ ์งํ๋ค.
- 1๋ฒ ์ฝ๋ ์คํ์ด ์ผ์์ ์ง๋๋ ๋์, ๋์ผํ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋์์ฑ ์ฝ๋๊ฐ ์คํ๋๋ค. ์๋ฅผ๋ค์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์ธ ์๋ก์ด ์ฌ์ง ๊ฐค๋ฌ๋ฆฌ ๋ชฉ๋ก์ ๊ณ์ํด์ ์ ๋ฐ์ดํธ ํ ์ ์๋ค. ์ด๋ฐ ์ฝ๋๋ await ๋ก ํ์๋ ๋ค์ ์ผ์์ ์ง ์ง์ ๊น์ง ํน์ ์คํ ์๋ฃ ๋ ๋๊น์ง ์คํ๋๋ค.
- listPhotos(inGallery: ) ๊ฐ ๋ฐํ๋๋ฉด ์ ์ฝ๋๋ ํด๋น ์ง์ ์์ ์์ํ์ฌ ๊ณ์ํด์ ์คํ๋๋ค. ์ฆ await ์ฝ๋ ๋ค์์ค์ธ, ๋ฐํ๊ฐ์ photoNames์ ํ ๋นํ๋ ์ฝ๋๋ฅผ ์งํํ๋ค.
- sortedNames ๋ฐ name ์ ์ ์ํ๋ ์ค์ ์ผ๋ฐ์ ์ธ ๋๊ธฐ์ฝ๋ ์ด๋ฏ๋ก, ๊ฐ๋ฅํ ์ ์ง ์ง์ ์ ์๋ค.
- ๋ค์ await๋ downloadPhoto(named: ) ๋ฉ์๋์ ๋ํ ํธ์ถ์ ํ์ํ๋ค. ์ด ์ฝ๋๋ ํด๋น ๋ฉ์๋๊ฐ ๋ฐํ ๋ ๋๊น์ง ์คํ์ ๋ค์ ์ผ์์ ์งํ์ฌ ๋ค๋ฅธ ๋์์ฑ ์ฝ๋๊ฐ ์คํ๋๋๋ก ํ๋ค.
- 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