Bibi's DevLog ๐ค๐
[Swift Language Guide] Concurrency (async/await, task, actor) ๋ณธ๋ฌธ
[Swift Language Guide] Concurrency (async/await, task, actor)
๋น๋น bibi 2023. 4. 16. 21:33
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/
์ ๊ณต์๋ฌธ์๋ฅผ ๋ฒ์ญํ ๋ด์ฉ์ ๋๋ค.
๋์์ฑ : ๋น๋๊ธฐ ์์ ์ํํ๊ธฐ.
๋ณ๋ ฌ(parallel) ๋๋ ๋น๋๊ธฐ(asynchronous) ์ฝ๋๋ ๋ณต์ก๋ ์ฆ๊ฐ๋ผ๋ ๋น์ฉ์ ๊ฐ์ ธ์จ๋ค.
Swift์์๋ ์ปดํ์ผ ํ์ ๊ฒ์ฌ๊ฐ ๊ฐ๋ฅํ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐ์์ ์๋๋ฅผ ํํํ ์ ์๋ค - ์๋ฅผ ๋ค์ด actor๋ฅผ ์ฌ์ฉํด mutable state์ ์์ ํ๊ฒ ์ ๊ทผํ ์ ์๋ค.
Swift๋ ์ธ์ด ์์ค์์ ๋น๋๊ธฐ ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์ปดํ์ผ ํ์์ ์ก์ ์ ์๋๋ก ๋๋๋ค.
Swift์ ๋์์ฑ ๋ชจ๋ธ์ ์ฐ๋ ๋ ์์ ๊ตฌ์ถ๋์ง๋ง, ์ฐ๋ ๋์ ์ง์ ์ํธ์์ฉํ์ง๋ ์๋๋ค.
completion handler๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ์กด ์ฝ๋
listPhotos(inGallery: "Summer Vacation") { photoNames in
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
downloadPhoto(named: name) { photo in
show(photo)
}
}
ํด๋ก์ ๋ฅผ ์ค์ฒฉํด ์ฌ์ฉํ๋ฏ๋ก ๊ฐ๋ ์ฑ์ด ์ ์ข์์ง๊ณ , ๋ณต์กํด์ง๋ค.
๋น๋๊ธฐ ํจ์์ ์ ์ ๋ฐ ํธ์ถ
๋น๋๊ธฐ ํจ์/๋ฉ์๋ : ์คํ ์ค ์ผ์์ ์งํ ์ ์๋ ํน์ํ ์ข
๋ฅ์ ํจ์/๋ฉ์๋๋ฅผ ์๋ฏธํจ.
๋ณดํต์ ํจ์(๋๊ธฐ์) ์ ์๋ฃ๋ ๋๊น์ง ์คํ๋๊ฑฐ๋, ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฑฐ๋, ๋ฐํ๋์ง ์๋ ์์ผ๋ก ๋์ํ๋ค. ๋น๋๊ธฐ ํจ์๋ ์ด๋ฐ ์์ผ๋ก ๋์ํ์ง๋ง, ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ ์ด๋ค ์์
์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ผ์์ ์ง๋ฅผ ํ ์ ์๋ค๋ ์ ์ด๋ค.
๋น๋๊ธฐ ํจ์๋ฅผ ์ ์ํ๊ธฐ ์ํด์๋ ํ๋ผ๋ฏธํฐ ์ ์ธ๊ณผ ->
์ฌ์ด์ async
ํค์๋๋ฅผ ์์ฑํ๋ค.
์๋ฌ๋ฅผ ๋์ง๋ ๋น๋๊ธฐ ํจ์๋ async throws
์์ผ๋ก ์์ฑํ๋ค.
func listPhotos(inGallery name: String) async -> [String] {
let result = // ... some asynchronous networking code ...
return result
}
๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๋ฉด, ๋ฉ์๋๊ฐ ๋ฐํ๋ ๋๊น์ง ์คํ์ด ์ค์ง๋๋ค.
์ผ์์ ์ง๊ฐ ๋ฐ์ํ ์ ์๋ ๋ถ๋ถ์ ํธ์ถํ ๋์๋ ์์ await
ํค์๋๋ฅผ ์์ฑํ๋ค. (์๋ฌ๊ฐ ๋ฐ์ํ ์ ์๋ ํจ์๋ฅผ ํธ์ถํ ๋, try
๋ฅผ ์์ฑํ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค)
์คํ ํ๋ฆ์ด ์ผ์์ ์งํ๋ ๊ฒฝ์ฐ๋ ์ค์ง ๋ค๋ฅธ ๋น๋๊ธฐ ๋ฉ์๋๋ฅผ ํธ์ถํ์ ๋์ด๋ค - ์ผ์์ ์ง๋ ์ ๋ ์๋ฌต์ ์ด๊ฑฐ๋ ์ ์ ์ ์ด์ง ์๋ค. ์ฆ ๋ชจ๋ ๊ฐ๋ฅํ ์ผ์์ ์ง ์ง์ ์ด await
๋ก ํ์๋๋ค.
์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ ๊ฐค๋ฌ๋ฆฌ์ ๋ชจ๋ ์ฌ์ง์ ์ด๋ฆ์ ๊ฐ์ ธ์จ ๋ค์ ์ฒซ ๋ฒ์งธ ์ฌ์ง์ ๋ณด์ฌ์ค๋ค:
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:)
ํจ์๋ฅผ ํธ์ถํ๊ณ , ๊ทธ ํจ์๊ฐ ๋ฐํ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์คํ์ ์ผ์์ ์งํ๋ค. - ์ด ์ฝ๋์ ์คํ์ด ์ค์ง๋ ๋์, ๊ฐ์ ํ๋ก๊ทธ๋จ์ ์๋ ๋ค๋ฅธ ๋ช๋ช ๋์์ฑ ์ฝ๋๊ฐ ์คํ๋๋ค.
- ์๋ฅผ ๋ค์ด, ์ค๋ ๊ฑธ๋ฆฌ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์ด ์ ํฌํ ๊ฐค๋ฌ๋ฆฌ์ ๋ชฉ๋ก์ ๊ณ์ ์ ๋ฐ์ดํธํ ๊ฒ์ด๋ค.
- ๊ทธ ์ฝ๋๋
await
๋ก ํ์๋ ๋ค์ ์ผ์์ ์ง ์ง์ ์ ๋๋ฌํ ๋๊น์ง, ๋๋ ์๋ฃ๋ ๋๊น์ง ์คํ๋ ๊ฒ์ด๋ค.
listPhotos(inGallery:)
๊ฐ ๋ฐํ๋ ํ, ์ด ์ฝ๋๋ ๊ทธ ์ง์ ๋ถํฐ ์คํ์ ๊ณ์ํ ๊ฒ์ด๋ค.photoNames
์ ๋ฐํ๋ ๊ฐ์ ํ ๋นํ ๊ฒ์ด๋ค.sortedNames
์name
์ ์ ์๋ ์ฝ๋๋ ์ผ๋ฐ์ ์ธ ๋๊ธฐ ์ฝ๋์ด๋ค. ๋ฐ๋ผ์ ์ด๋ค ์ผ์์ ์ง๋ ๋ฐ์ํ์ง ์๋๋ค.- ๋ค์
await
๊ฐdownloadPhoto(named:)
ํจ์ ํธ์ถ์ ํ์๋์ด ์๋ค. ์ด ์ฝ๋๋ ์ด ํจ์๊ฐ ๋ฐํ๋ ๋๊น์ง ์คํ์ ๋๋ค์ ์ผ์์ ์งํ ๊ฒ์ด๋ฉฐ, ๋ค๋ฅธ ๋์์ฑ ์ฝ๋๊ฐ ์คํ๋ ๊ธฐํ๋ฅผ ์ค ๊ฒ์ด๋ค. downloadPhoto(named:)
๊ฐ ๋ฐํ๋ ํ์, ๊ทธ ๋ฐํ๊ฐ์photo
์ ํ ๋น๋๋ฉฐshow(_:)
๊ฐ ํธ์ถ๋ ๋์ ์๊ท๋จผํธ๋ก์ ์ ๋ฌ๋ ๊ฒ์ด๋ค.
์ฝ๋ ๋ด์์ ์ผ์์ ์ง๊ฐ ๋ฐ์ํ ์ ์๋ ์ง์ ์ await
๋ก ํ์๋์ด, ๋น๋๊ธฐ ํจ์ ๋๋ ๋ฉ์๋๊ฐ ๋ฐํ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ํ์ฌ ์ฝ๋ ์กฐ๊ฐ์ด ์คํ์ ์ค์ง์ํฌ ์ ์์์ ๋ํ๋
๋๋ค. ์ด๊ฒ์ ๋ํ ์ฐ๋ ๋ ์๋ณด(yielding the thread) ๋ผ๊ณ ๋ ๋ถ๋ฆฌ๋๋ฐ, ๊ทธ ์ด์ ๋ Swift๊ฐ ๋ท๋จ์์ ํ์ฌ ์ฐ๋ ๋์ ์ฝ๋ ์คํ์ ์ค์ง์ํค๊ณ ๊ทธ ์ค๋ ๋์ ๋ค๋ฅธ ์ฝ๋๋ฅผ ๋์ ์คํ์ํค๊ธฐ ๋๋ฌธ์
๋๋ค.
await
๋ก ํ์๋ ์ฝ๋๋ ์คํ์ ์ผ์์ ์งํ ์ ์์ด์ผ ํ๋ฏ๋ก, ํ๋ก๊ทธ๋จ์ ํน์ ์์น์์๋ง ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค :
- ๋น๋๊ธฐ ํจ์/๋ฉ์๋/ํ๋กํผํฐ์ body์์
@main
์ผ๋ก ํ์๋ ๊ตฌ์กฐ์ฒด, ํด๋์ค, ์ด๊ฑฐํ์ static main() ํจ์์์- Unstructured Concurrency์ ๋ด์ฉ๊ณผ ๊ฐ์ด, ๊ตฌ์กฐํ๋์ง ์์ child task์์
์ค๋จ๋ ์ ์๋ ์ง์ ์ฌ์ด์ ์ฝ๋๋, ๋ค๋ฅธ ๋์์ฑ ์ฝ๋์ ๋ฐฉํด ์์ด ์์ฐจ์ ์ผ๋ก(sequentially) ์คํ๋๋ค. ์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ ํ ๊ฐค๋ฌ๋ฆฌ์์ ๋ค๋ฅธ ๊ฐค๋ฌ๋ฆฌ๋ก ์ฌ์ง์ ์ฎ๊ธด๋ค.
let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
add(firstPhoto, toGallery: "Road Trip")
// At this point, firstPhoto is temporarily in both galleries.
remove(firstPhoto, fromGallery: "Summer Vacation")
add(_:toGallery:)
ํธ์ถ๊ณผ remove(_:fromGallery:)
ํธ์ถ ์ฌ์ด์ ๋ค๋ฅธ ์ฝ๋๋ฅผ ์คํํ ๋ฐฉ๋ฒ์ด ์๋ค. ๊ทธ ์๊ฐ ๋์, ์ฒซ ๋ฒ์งธ ์ฌ์ง์ด ๋ ๊ฐค๋ฌ๋ฆฌ ๋ชจ๋์ ๋ํ๋ ์ผ์์ ์ผ๋ก ์ฑ์ ๋ถ๋ณ์ฑ(invariant) ์ค ํ๋๋ฅผ ์๋ฐฐํ๋ค. ๋ ์ด์์ await
๊ฐ ์ถ๊ฐ๋์ด์ ์ ๋จ์ ๋ช
ํํ ํ๊ธฐ ์ํด, ํด๋น ์ฝ๋๋ ๋๊ธฐ ํจ์๋ก ๋ฆฌํฉํ ๋งํ ์ ์๋ค:
func move(_ photoName: String, from source: String, to destination: String) {
add(photoName, toGallery: destination)
remove(photoName, fromGallery: source)
}
// ...
let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
move(firstPhoto, from: "Summer Vacation", to: "Road Trip")
์์ ์์์์, move(_:from:to:)
ํจ์๊ฐ ๋๊ธฐ ํจ์์ด๊ธฐ ๋๋ฌธ์, ๋น์ ์ ์ด๋ค ์ผ์์ ์ง๋ ๋ฐ์ํ์ง ์์ ๊ฒ์์ ํ์ ํ ์ ์๋ค. ๋์ค์ ๋ง์ฝ ์ด ํจ์์ ์ผ์์ ์ง๋ ์ ์๋ ๋์์ฑ ์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉด, ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๋ ๋์ ์ปดํ์ผ ํ์ ์๋ฌ๋ฅผ ๋ฐ์ ์ ์๋ค.
์ฐธ๊ณ
Task.sleep(until:tolerance:clock:)
๋ฉ์๋๋ ๋์์ฑ์ด ์ด๋ป๊ฒ ๋์ํ๋์ง ๋ฐฐ์ฐ๊ธฐ ์ํ ๊ฐ๋จํ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์ ์ฉํ๋ค. ์ด ๋ฉ์๋๋ ์๋ฌด ๊ฒ๋ ํ์ง ์์ง๋ง, ๋ฐํ๋๊ธฐ ์ ์ ์ต์ํ ์ฃผ์ด์ง ์๊ฐ๋งํผ ๊ธฐ๋ค๋ฆฐ๋ค. ์๋๋ ์์ listPhotos(inGallery:)
ํจ์์ sleep(until:tolerance:clock:)
๋ฅผ ์ฌ์ฉํ์ฌ ๋คํธ์ํฌ ์์
์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ ํ๋ด๋ธ ๊ฒ์ด๋ค :
func listPhotos(inGallery name: String) async throws -> [String] {
try await Task.sleep(until: .now + .seconds(2), clock: .continuous)
return ["IMG001", "IMG99", "IMG0404"]
}
๋น๋๊ธฐ ์ํ์ค
์ด์ ์น์
์ listPhotos(inGallery:)
ํจ์๋, ๋ฐฐ์ด์ ๋ชจ๋ ์์๊ฐ ์ค๋น๋ ์ดํ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ ์ฒด ๋ฐฐ์ด์ ํ ๋ฒ์ ๋ฐํํ๋ค.
๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก, ๋น๋๊ธฐ ์ํ์ค(asynchronous sequence) ๋ฅผ ์ฌ์ฉํด ํ ๋ฒ์ ์ปฌ๋ ์
์ ํ ์์๋ฅผ ๊ธฐ๋ค๋ฆด ์ ์๋ค. ์๋๋ ๋น๋๊ธฐ ์ํ์ค๋ฅผ ๋ฐ๋ณต(iterating over)ํ๋ ๋ชจ์ต์ด๋ค:
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
๋ฐ๋ณต๋ฌธ์์ ์ฌ์ฉ์ ์ ์ ํ์
์ ์ฌ์ฉํ ์ ์๋ค.
๋ณ๋ ฌ๋ก ๋น๋๊ธฐ ํจ์ ํธ์ถํ๊ธฐ
await
๋ก ์ ์ธ๋ ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํ ๋ฒ์ ํ ์กฐ๊ฐ์ ์ฝ๋๋ง ์คํํ๋ค. ๋น๋๊ธฐ ์ฝ๋๊ฐ ์คํ๋๋ ๋์, ํธ์ถ์๋ ๋ค์ ์ฝ๋ ์ค๋ก ์ด๋ํ๊ธฐ ์ ์ ๊ทธ ์ฝ๋๊ฐ ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค.
์๋ฅผ ๋ค์ด, ๊ฐค๋ฌ๋ฆฌ์์ ์ฒ์๋ถํฐ 3๊ฐ์ ์ฌ์ง์ ๊ฐ์ ธ์ค๊ธฐ ์ํด, ์๋์ ๊ฐ์ด downloadPhoto(named:)
ํจ์๋ฅผ await
๋ก ์ธ ๋ฒ ํธ์ถํ ์ ์์ต๋๋ค:
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)
์ด ๋ฐฉ๋ฒ์ ์ค์ํ ์ฝ์ ์ด ์์ต๋๋ค: ๋ค์ด๋ก๋๊ฐ ๋น๋๊ธฐ์ด๊ณ ๊ทธ ์งํ ๋์ ๋ค๋ฅธ ์์
์ด ๋ฐ์ํ ์ ์๋๋ก ๋์ด ์์ง๋ง, ํ ๋ฒ์ ์ค์ง ํ๋์ downloadPhoto(named:)
๋ง์ด ์คํ๋ฉ๋๋ค. ๊ฐ๊ฐ์ ์ฌ์ง์ ๋ค์ ๊ฒ์ ๋ค์ด๋ก๋๊ฐ ์์๋๊ธฐ ์ ์ ์์ ํ ๋ค์ด๋ก๋๋ฉ๋๋ค. ํ์ง๋ง, ์ด๋ฌํ ์์
์ ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์์ต๋๋ค - ๊ฐ๊ฐ์ ์ฌ์ง์ ๋
๋ฆฝ์ ์ผ๋ก ๋ค์ด๋ก๋๋ ์ ์๊ณ , ์ฌ์ง์ด ๋์์๋ ๊ฐ๋ฅํฉ๋๋ค.
๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๊ณ ์ฃผ๋ณ์ ์ฝ๋์ ๋ณ๋ ฌ๋ก ์คํ๋๋๋ก ํ๋ ค๋ฉด, ์์๋ฅผ ์ ์ํ ๋ 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)
์ด ์์์์๋, 3๊ฐ์ downloadPhoto(named:)
ํธ์ถ์ด ๋ชจ๋ ์์ ์์
์ด ๋๋๋ ๊ฒ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์์๋ฉ๋๋ค. ๋ง์ฝ ์ถฉ๋ถํ ์์คํ
๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ฉด, ์ด ์์
๋ค์ ๋์์ ์คํ๋ฉ๋๋ค. ์ด ํจ์ ํธ์ถ ์ค ์ด๋ค ๊ฒ๋ await
๋ก ํ์๋์ง ์์์ต๋๋ค. ์๋ํ๋ฉด, ์ฝ๋๊ฐ ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํด ์ผ์์ค๋จ๋์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋์ , photos
๊ฐ ์ ์๋ ์ค๊น์ง ์คํ์ด ๊ณ์๋ฉ๋๋ค. ์ด ์ค์์๋ ํ๋ก๊ทธ๋จ์ด ๋น๋๊ธฐ ํธ์ถ๋ค์ ๊ฒฐ๊ณผ๋ฅผ ํ์๋ก ํ๋ฏ๋ก, ์ธ ๊ฐ์ ์ฌ์ง์ด ๋ค์ด๋ก๋๊ฐ ๋ค ๋ ๋๊น์ง ์คํ์ ์ผ์์ ์งํ๊ธฐ ์ํด await
๋ฅผ ์์ฑํฉ๋๋ค.
์ด๋ฌํ ๋ ๊ฐ์ง ์ ๊ทผ๋ฒ์ ์ฐจ์ด๋ ์ด๋ ๊ฒ ์๊ฐํ ์ ์์ต๋๋ค:
await
๋ก ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ๋, ์ดํ์ ์ฝ๋๋ค์ด ๊ทธ ํจ์์ ๊ฒฐ๊ณผ์ ์์กดํ๊ณ ์์ ๋์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์์ฐจ์ ์ผ๋ก ์ํ๋๋ ์์ ์ด ์์ฑ๋ฉ๋๋ค.async-let
์ผ๋ก ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ๋, ์ดํ ์ฝ๋์์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ์๋ก ํ์ง ์์ ๋ ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ณ๋ ฌ๋ก ์คํ๋๋ ์์ ์ด ์์ฑ๋ฉ๋๋ค.await
์async-let
์ ๋ชจ๋ ์์ ์ด ์ผ์์ ์ง๋๋ ๋์ ๋ค๋ฅธ ์ฝ๋๊ฐ ์คํ๋๋ ๊ฒ์ ํ๋ฝํฉ๋๋ค.- ๋ ๊ฒฝ์ฐ ๋ชจ๋, ์ผ์์ ์ง๊ฐ ๋ฐ์ํ ์ ์๋ ์ง์ ์
await
๋ก ํ์ํจ์ผ๋ก์จ ์คํ์ด ์ค์ง๋ ์ ์๊ณ , ํ์ํ ๊ฒฝ์ฐ ๋น๋๊ธฐ ํจ์๊ฐ ๋ฐํ๋ ๋๊น์ง ์ค์ง๋ ์ ์์์ ๋ํ๋ด์ผ ํฉ๋๋ค.
๋น์ ์ ์ด ๋ ๋ฐฉ๋ฒ์ ๊ฐ์ ์ฝ๋์ ํจ๊ป ์์ด์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
Tasks์ Task Groups
Task๋ ๋น์ ์ ํ๋ก๊ทธ๋จ์ ์ผ๋ถ๋ก ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ ์ ์๋ ์์
๋จ์๋ฅผ ์๋ฏธํฉ๋๋ค. ๋ชจ๋ ๋น๋๊ธฐ ์ฝ๋๋ ์ด๋ค task์ ์ผ๋ถ๋ก์ ์คํ๋ฉ๋๋ค.
์ด์ ์น์
์์ ์ค๋ช
ํ async-let
๋ฌธ๋ฒ์ ๊ฒฝ์ฐ, ๋น์ ์๊ฒ child task๋ฅผ ๋ง๋ค์ด ์ค๋๋ค. ๋น์ ์ ๋ํ task group์ ๋ง๋ค๊ณ ๊ฑฐ๊ธฐ์ ์์task๋ค์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์ฐ์ ์์์ ์ทจ์์ ๋ํ ๋ ๋ง์ ์ ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ฉฐ, ๋์ ์ธ ์ซ์์ task๋ค์ ๋ง๋ค ์ ์๊ฒ ํด ์ค๋๋ค.
task๋ค์ ๊ณ์ธต์ผ๋ก ์ ๋ฆฌ๋ฉ๋๋ค. task group์ ๊ฐ๊ฐ์ task๋ ๊ฐ์ ๋ถ๋ชจtask๋ฅผ ๊ฐ์ง๋ฉฐ, ๊ฐ๊ฐ์ task๋ ์์task๋ค์ ๊ฐ์ง ์ ์์ต๋๋ค. task๋ค๊ณผ task group๋ค ์ฌ์ด์ ๋ช
์์ ์ธ ๊ด๊ณ๋ก ์ธํด, ์ด๋ฌํ ์ ๊ทผ๋ฐฉ์์ ๊ตฌ์กฐํ๋ ๋์์ฑ(structured concurrency) ์ด๋ผ๊ณ ํฉ๋๋ค. ๋น์ ์ด ์ ํ์ฑ์ ๋ํ ์ฝ๊ฐ์ ์ฑ
์์ ๊ฐ๊ธด ํ์ง๋ง, task๋ค ์ฌ์ด์ ๋ช
์์ ์ธ parent-child ๊ด๊ณ ๋๋ถ์ Swift๊ฐ ์ทจ์ ์ ํ(propagating cancellation)์ ๊ฐ์ ๋ช๋ช ๋์์ ๋น์ ์ ์ํด ํด์ค ์ ์๊ฒ ๋ฉ๋๋ค. ๋ํ Swift๊ฐ ์ปดํ์ผ ํ์์ ๋ช๋ช ์๋ฌ๋ค์ ๊ฐ์งํ ์ ์๊ฒ ๋ฉ๋๋ค.
await withTaskGroup(of: Data.self) { taskGroup in
let photoNames = await listPhotos(inGallery: "Summer Vacation")
for name in photoNames {
taskGroup.addTask { await downloadPhoto(named: name) }
}
}
task group์ ๋ํ ๋ ์์ธํ ์ ๋ณด๋ TaskGroup ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
๊ตฌ์กฐํ๋์ง ์์ ๋์์ฑ (Unstructured Concurrency)
์ ์น์
์ ์ค๋ช
๋ ๋์์ฑ์ ๋ํ ๊ตฌ์กฐํ๋ ์ ๊ทผ์ ๋ํด, Swift๋ ๊ตฌ์กฐํ๋์ง ์์ ๋์์ฑ ๋ํ ์ง์ํฉ๋๋ค. task group์ ์ํ task์ ๋ฌ๋ฆฌ, unstructured task ๋ ๋ถ๋ชจ task๊ฐ ์์ต๋๋ค. ๋น์ ์ ํ๋ก๊ทธ๋จ์ ํ์ํ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ unstructured task๋ฅผ ๊ด๋ฆฌํ๋ ์์ ํ ์ ์ฐ์ฑ์ ๊ฐ์ง ์ ์์ต๋๋ค. ํ์ง๋ง ๊ทธ ์ ํ์ฑ์ ๋ํ ์์ ํ ์ฑ
์ ๋ํ ๊ฐ์ง๊ฒ ๋ฉ๋๋ค.
ํ์ฌ actor์์ ์คํ๋๋ unstructured task๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋, Task.init(priority:operation:)
์ด๋์
๋ผ์ด์ ๋ฅผ ํธ์ถํ์ญ์์ค. ํ์ฌ actor์ ํฌํจ๋์ง ์๋ unstructured task(๋ณดํต detached task ๋ผ๊ณ ํน์ ํด ๋ถ๋ฆ
๋๋ค)๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋, Task.detached(priority:operation:)
ํด๋์ค ๋ฉ์๋๋ฅผ ํธ์ถํ์ญ์์ค. ์ด ๋ ์์
์ ๋ชจ๋ ๋น์ ์ด ์ํธ์์ฉ(๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฑฐ๋ ์ทจ์ํ๋ ๋ฑ)ํ ์ ์๋ task๋ฅผ ๋ฐํํฉ๋๋ค.
let newPhoto = // ... some photo data ...
let handle = Task {
return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}
let result = await handle.value
detached task์ ๊ด๋ฆฌ์ ๋ํ ๋ ๋ง์ ์ ๋ณด๋ Task ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
Task ์ทจ์ (Task Cancellation)
Swift ๋์์ฑ์ ํ์กฐ์ ์ธ ์ทจ์ ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค. ๊ฐ๊ฐ์ task๋ ์คํ์ ์์ด ์ ์ ํ ์์ ์์ ์ทจ์๋์๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ , ์ ์ ํ ๋ฐฉ์์ผ๋ก ์ทจ์์ ์๋ตํฉ๋๋ค. ๋น์ ์ด ํ๊ณ ์๋ ์์ ์ ๋ฐ๋ผ, ์ด๊ฒ์ ๋ณดํต ์๋์ ๊ฒ๋ค ์ค ํ๋๋ฅผ ์๋ฏธํฉ๋๋ค:
CancellationError
์ ๊ฐ์ ์๋ฌ ๋์ง๊ธฐnil
๋๋ ๋น ์ปฌ๋ ์ ๋ฐํํ๊ธฐ- ๋ถ๋ถ์ ์ผ๋ก ์๋ฃ๋ work ๋ฐํํ๊ธฐ
์ทจ์๋ฅผ ํ์ธํ๊ธฐ ์ํด, task๊ฐ ์ทจ์๋์์ ๋ CancellationError
๋ฅผ ๋์ง๋ Task.checkCancellation()
์ ํธ์ถํ๊ฑฐ๋, ํน์ Task.isCancelled
์ ๊ฐ์ ํ์ธํด ๋น์ ์ ์ฝ๋์ ์ทจ์๋ฅผ ์ฒ๋ฆฌํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ๊ฐค๋ฌ๋ฆฌ๋ก๋ถํฐ ์ฌ์ง์ ๋ค์ด๋ก๋ํ๋ ์์
์ ๋ถ๋ถ์ ์ธ ๋ค์ด๋ก๋๋ฅผ ์ญ์ ํ๊ณ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ ์ข
๋ฃํด์ผ ํ ์ ์์ต๋๋ค.
์ทจ์๋ฅผ ์๋์ผ๋ก ์ ํํ๋ ค๋ฉด Task.cancel()
์ ํธ์ถํ์ญ์์ค.
Actors
๋น์ ์ ํ๋ก๊ทธ๋จ์ ๋
๋ฆฝ๋ ๋์์ฑ ์กฐ๊ฐ์ผ๋ก ๋๋๊ธฐ ์ํด task๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค. task๋ ์๋ก๋ก๋ถํฐ ๋
๋ฆฝ๋์ด ์์ผ๋ฉฐ, ์ด๋ ๋์์ ์คํ๋๋๋ผ๋ ์์ ํ ์ ์๊ฒ ํฉ๋๋ค. ํ์ง๋ง ๊ฐ๋์ task๋ค ์ฌ์ด์ ์ด๋ค ์ ๋ณด๋ฅผ ๊ณต์ ํด์ผ ํ ํ์๊ฐ ์์ ๊ฒ์
๋๋ค. Actors๋ ๋น์ ์ด ๋์์ฑ ์ฝ๋ ์ฌ์ด์ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๊ณต์ ํ ์ ์๋๋ก ํด ์ค๋๋ค.
ํด๋์ค์ ๊ฐ์ด, actors๋ ์ฐธ์กฐ ํ์
์
๋๋ค. ๋ฐ๋ผ์ ๊ฐ ํ์
๊ณผ ์ฐธ์กฐ ํ์
์ ๋น๊ตํ๋ Classes Are Reference Types ์ ๋ด์ฉ์ actor์๋ ํด๋์ค์ฒ๋ผ ๋์ผํ๊ฒ ์ ์ฉ๋ฉ๋๋ค.
ํด๋์ค์ ๋ค๋ฅด๊ฒ, actors๋ ํ ๋ฒ์ ์ค์ง ํ๋์ task๋ง์ด mutableํ ์ํ์ ์ ๊ทผํ๋๋ก ํ์ฉํฉ๋๋ค. ์ด๋ ๋ค์์ task๋ค์ด 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
}
}
actor๋ actor
ํค์๋๋ก ์๊ฐํ๋ฉฐ, ๊ทธ ์ ์๋ฅผ ์ค๊ดํธ ๋ด์ ์์ฑํฉ๋๋ค. TemperatureLogger
actor๋ actor ๋ฐ๊นฅ์ ๋ค๋ฅธ ์ฝ๋๊ฐ ์ ๊ทผํ ์ ์๋ ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๋ฉฐ, max
ํ๋กํผํฐ๋ ์ค์ง actor ๋ด๋ถ์ ์ฝ๋๋ง ์ต๋๊ฐ์ ๋ฐ๊ฟ ์ ์๋๋ก ์ ํํฉ๋๋ค.
actor์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ๋๋ ๊ตฌ์กฐ์ฒด์ ํด๋์ค์ ๊ฐ์ ์ด๋์
๋ผ์ด์ ๋ฌธ๋ฒ์ ์ฌ์ฉํฉ๋๋ค. actor์ ํ๋กํผํฐ๋ ๋ฉ์๋์ ์ ๊ทผํ ๋, await
ํค์๋๋ฅผ ์ฌ์ฉํด ์ผ์์ ์ง๊ฐ ์ผ์ด๋ ์ ์๋ ์ง์ ์ ํ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด:
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
// Prints "25"
์ด ์์์์, logger.max
์ ์ ๊ทผํ๋ ๊ฒ์ ์ผ์์ ์ง๊ฐ ์ผ์ด๋ ์ ์๋ ์ง์ ์
๋๋ค. ์๋ํ๋ฉด actor๋ ์์ ์ mutableํ ์ํ์ ํ ๋ฒ์ ์ค์ง ํ๋์ task๊ฐ ์ ๊ทผํ๋๋ก ์ ํํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ง์ฝ ๋ค๋ฅธ task๊ฐ ์ด๋ฏธ logger์ ์ํธ์์ฉํ๊ณ ์๋ค๋ฉด, ์ด ์ฝ๋๋ ๊ทธ ํ๋กํผํฐ์ ์ ๊ทผํ๊ธฐ ์ํด ๊ธฐ๋ค๋ฆฌ๋๋ผ ์ฝ๋๊ฐ ์ผ์์ ์งํ๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ฉด, actor์ ์ผ๋ถ์ธ ์ฝ๋๋ actor์ ํ๋กํผํฐ์ ์ ๊ทผํ ๋ await
ํค์๋๋ฅผ ์์ฑํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ๊ธฐ์ TemperatureLogger
๋ฅผ ์๋ก์ด ์จ๋๋ก ๊ฐฑ์ ํ๋ ๋ฉ์๋๊ฐ ์์ต๋๋ค:
extension TemperatureLogger {
func update(with measurement: Int) {
measurements.append(measurement)
if measurement > max {
max = measurement
}
}
}
update(with:)
๋ฉ์๋๋ ์ด๋ฏธ actor ๋ด์์ ์คํ๋๊ณ ์์ต๋๋ค. ๋ฐ๋ผ์ ๊ทธ๊ฒ์ max
์ ๊ฐ์ ํ๋กํผํฐ์ ์ ๊ทผํ ๋ await
๋ฅผ ๋ถ์ด์ง ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ๋ํ ์ actor๊ฐ ์์ ์ mutableํ ์ํ์ ์ํธ์์ฉํ ๋ ํ ๋ฒ์ ์ค์ง ํ๋์ task๋ง์ ํ์ฉํ๋์ง ๊ทธ ์ด์ ๋ฅผ ๋ณด์ฌ์ค๋๋ค: actor์ ์ํ์ ๋ํ ์ด๋ค ๋ณ๊ฒฝ์ ์ผ์์ ์ผ๋ก ๋ถ๋ณ์ฑ(invariants)์ ๊นจ๋จ๋ฆฌ๊ธฐ ๋๋ฌธ์
๋๋ค. TemperatureLogger
actor๋ ์จ๋์ ๋ฆฌ์คํธ์ ์ต๊ณ ์จ๋๋ฅผ ๊ณ์ ์ถ์ ํ๊ณ ์์ผ๋ฉฐ, ์๋ก์ด ์จ๋๊ฐ ๊ธฐ๋ก๋์์ ๋ ์ต๊ณ ์จ๋๋ฅผ ๊ฐฑ์ ํฉ๋๋ค. ๊ฐฑ์ ์ค๊ฐ, ์ฆ ์ ์ธก์ ๊ฐ์ ๋ถ์ธ ํ์ max
๋ฅผ ๊ฐฑ์ ํ๊ธฐ ์ ์ฌ์ด์ TemperatureLogger
๋ ์ผ์์ ์ผ๋ก ์ผ๊ด์ฑ์ด ์๋ ์ํ๊ฐ ๋ฉ๋๋ค. ๋์์ ๊ฐ์ ์ธ์คํด์ค์ ์ฌ๋ฌ task๋ค์ด ์ํธ์์ฉํ๋ ๊ฒ์ ๋ง์์ผ๋ก์จ, ์๋์ ๊ฐ์ ์ฐ์๋ ์ฌ๊ฑด ๋ฐ์์ผ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ๋ง์ ์ ์์ต๋๋ค:
- ๋น์ ์ ์ฝ๋๊ฐ
update(with:)
๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ๋จผ์ , ๊ทธ๊ฒ์measurement
๋ฐฐ์ด์ ๊ฐ์ ๋ฐ๊พธ๊ฒ ๋ฉ๋๋ค. - ๋น์ ์ ์ฝ๋๊ฐ
max
๊ฐ์ ๋ฐ๊พธ๊ธฐ ์ ์, ๋ค๋ฅธ ๊ณณ์ ์ฝ๋๊ฐ ์จ๋ ๋ฐฐ์ด๊ณผ ์ต๋๊ฐ์ ์กฐํํฉ๋๋ค. - ๋น์ ์ ์ฝ๋๊ฐ
max
๊ฐ์ ๊ฐฑ์ ์ ๋๋ ๋๋ค.
์์ ๊ฐ์ ๊ฒฝ์ฐ, ๋ค๋ฅธ ๊ณณ์์ ์คํ์ค์ธ ์ฝ๋๋ ๋ถ์ ํํ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ๋ฉ๋๋ค. ์๋ํ๋ฉด actor์ ๋ํ ์ ๊ทผ์ด ๋ฐ์ดํฐ๊ฐ ์ผ์์ ์ผ๋ก ์ ํจํ์ง ์์ ์์ ์ update(with:)
ํธ์ถ ๋์ค์ interleave(๊ต์ฐจ๋์ด) ์ผ์ด๋ฌ๊ธฐ ๋๋ฌธ์
๋๋ค. Swift actor๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ฐ ๋ฌธ์ ๋ ์๋ฐฉ๋ ์ ์์ต๋๋ค. ์๋ํ๋ฉด ํ ๋ฒ์ ์ํ๊ฐ์ ๋ํ ํ๋์ ์์
๋ง์ ํ์ฉํ๊ณ , await
๊ฐ ์ผ์์ค๋จ ์ง์ ์ ํ์ํ ์ง์ ์์๋ง ์ฝ๋์ ์ค๋จ์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. update(with:)
๋ ์ด๋ค ์ผ์์ค๋จ ์ง์ ๋ ํฌํจํ์ง ์์ผ๋ฏ๋ก, ์ด๋ค ๋ค๋ฅธ ์ฝ๋๋ ์
๋ฐ์ดํธ ์ค๊ฐ์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค.
interleave : ์ด๋ค ํ๋ก๊ทธ๋จ์ ์ผ๋ถ๋ฅผ ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ ๋ผ์ ๋ฃ๋ ์ผ. ๊ต์ฐจ๋ก ๋ฐฐ์นํ๋ ์ผ?
๋ง์ฝ ๋น์ ์ด actor ๋ฐ๊นฅ์์ ์ด๋ฌํ ํ๋กํผํฐ์ ์ ๊ทผํ๋ ค ํ๋ค๋ฉด(๋ง์น ํด๋์ค์ ์ธ์คํด์ค์ ์ ๊ทผํ๋ฏ์ด), ๋น์ ์ ์ปดํ์ผ ํ์ ์๋ฌ๋ฅผ ๋ง๋๊ฒ ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด :
print(logger.max) // Error
await
ํค์๋ ์์ฑ ์์ด logger.max
์ ์ ๊ทผํ๋ ๊ฒ์ ์คํจํฉ๋๋ค. ์๋ํ๋ฉด actor์ ํ๋กํผํฐ๋ค์ actor์ ๋
๋ฆฝ๋ local state์ ์ผ๋ถ์ด๊ธฐ ๋๋ฌธ์
๋๋ค. Swift๋ ์ค์ง actor ๋ด๋ถ์ ์ฝ๋๋ง actor์ local state์ ์ ๊ทผํ ์ ์์์ ๋ณด์ฅํฉ๋๋ค. ์ด๋ฌํ ๋ณด์ฅ์ actor ๊ฒฉ๋ฆฌ(actor isolation) ๋ผ๊ณ ํฉ๋๋ค.
Sendable Types
task์ actor๋ ๋น์ ์ ํ๋ก๊ทธ๋จ์ด ์์ ํ๊ฒ ๋์์ ์ผ๋ก ์คํ๋ ์ ์๋๋ก ๋๋๋ ๊ฒ์ ๋์ต๋๋ค. task๋ actor์ ์ธ์คํด์ค ๋ด๋ถ์์, mutableํ ์ํ(ํ๋กํผํฐ๋ ๋ณ์ ๊ฐ์)๋ฅผ ํฌํจํ๋ ํ๋ก๊ทธ๋จ์ ๋ถ๋ถ์ ๋์์ฑ ๋๋ฉ์ธ(concurrency domain) ์ด๋ผ๊ณ ๋ถ๋ฆ
๋๋ค. ์ด๋ค ์ข
๋ฅ์ ๋ฐ์ดํฐ๋ ๋์์ฑ ๋๋ฉ์ธ ๊ฐ์ ๊ณต์ ๋ ์ ์์ต๋๋ค. ๊ทธ ์ด์ ๋ ๊ทธ ๋ฐ์ดํฐ๊ฐ mutableํ ์ํ๋ฅผ ํฌํจํ์ง๋ง ์ค๋ณต ์ ๊ทผ(overlapping access)์ผ๋ก๋ถํฐ ๋ณดํธํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค.
ํ๋์ ๋์์ฑ ๋๋ฉ์ธ์ผ๋ก๋ถํฐ ๋ค๋ฅธ ๋๋ฉ์ธ์ผ๋ก ๊ณต์ ๋ ์ ์๋ ํ์
์ sendable type ์ด๋ผ๊ณ ์๋ ค์ ธ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ทธ๊ฒ์ actor ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฑฐ๋ task์ ๊ฒฐ๊ณผ๋ก์ ๋ฐํ๋ ๋ ์๊ท๋จผํธ์ฒ๋ผ ์ ๋ฌ๋ ์ ์์ต๋๋ค. ์ด ์ฑํฐ ์ด์ ์ ์์๋ค์ sendability์ ๋ํด ์ด์ผ๊ธฐํ์ง ์์์ต๋๋ค. ๊ทธ ์ด์ ๋ ๊ทธ ์์๋ค์ด ๋์์ฑ ๋๋ฉ์ธ ๊ฐ์ ์ ๋ฌ ๋ฐ ๊ณต์ ๋์ด๋ ์์ ํ ๋ฐ์ดํฐ์ธ ๊ฐ๋จํ ๊ฐ ํ์
๋ง์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ฐ๋๋ก, ์ด๋ค ํ์
๋ค์ ๋์์ฑ ๋๋ฉ์ธ ์ฌ์ด์ ์ ๋ฌ๋๊ธฐ์ ์์ ํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, mutableํ ํ๋กํผํฐ๋ฅผ ํฌํจํ๋ฉฐ ๊ทธ ํ๋กํผํฐ์ ๋ํ ์ ๊ทผ์ ์ง๋ ฌํ(serialize)ํ์ง ์๋ ํด๋์ค๋, ๋น์ ์ด ๊ทธ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์๋ก ๋ค๋ฅธ task๊ฐ์ ์ ๋ฌํ ๋ ์์ธกํ ์ ์๊ณ ๋ถ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ๋ณ์ ์ ์์ต๋๋ค.
sendableํ ํ์
์ผ๋ก ํ์ํ๊ธฐ ์ํด์๋ Sendable
ํ๋กํ ์ฝ์ ์ฑํํด ์ ์ธํฉ๋๋ค. ์ด ํ๋กํ ์ฝ์ ์ด๋ค ์ฝ๋๋ ์๊ตฌํ์ง ์์ง๋ง, Swift๊ฐ ๊ฐ์ ํ๋ ์๋ฏธ์ ์๊ตฌ์ฌํญ(semantic requirements) ์ด ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก, sendableํ ํ์
์ด ๋๋ ๋ฐฉ๋ฒ์๋ ์ธ ๊ฐ์ง๊ฐ ์กด์ฌํฉ๋๋ค:
- ํ์ ์ด ๊ฐ ํ์ ์ด๋ฉฐ, ๊ทธ๊ฒ์ mutableํ ์ํ๊ฐ ๋ค๋ฅธ sendableํ ํ ์ดํฐ๋ก๋ถํฐ ๋ง๋ค์ด์ง - ์๋ฅผ ๋ค์ด, ๊ตฌ์กฐ์ฒด๊ฐ ์ ์ฅ ํ๋กํผํฐ๋ค๋ก ๊ตฌ์ฑ๋์ด ์๋๋ฐ, ๊ทธ ์ ์ฅํ๋กํผํฐ๋ค์ด sendableํ ๊ฒฝ์ฐ. ๋๋ ์ด๊ฑฐํ์ ์ฐ๊ด๊ฐ๋ค์ด sendableํ ๊ฒฝ์ฐ.
- ํ์ ์ด ์ด๋ค mutableํ ์ํ๋ ๊ฐ์ง ์์ผ๋ฉฐ, ๊ทธ๊ฒ์ immutableํ ์ํ๊ฐ ๋ค๋ฅธ sendableํ ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋ ๊ฒฝ์ฐ - ์๋ฅผ ๋ค์ด, ๊ตฌ์กฐ์ฒด๋ ํด๋์ค๊ฐ ์ค์ง ์ฝ๊ธฐ ์ ์ฉ(read-only) ํ๋กํผํฐ๋ง ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ.
- ํ์
์ด ๊ทธ๊ฒ์ mutableํ ์ํ์ ์์ ์ฑ์ ๋ณด์ฅํ๋ ์ฝ๋๋ฅผ ๊ฐ์ง ๊ฒฝ์ฐ. ์๋ฅผ ๋ค์ด
@MainActor
๋ก ํ์๋ ํด๋์ค๋, ํน์ ์ค๋ ๋๋ ํ์ ํ๋กํผํฐ์ ๋ํ ์ ๊ทผ์ ์ง๋ ฌํํ๋ ํด๋์ค
์๋ฏธ์ ์๊ตฌ์ฌํญ์ ๋ํ ๋ ์์ธํ ๋ด์ฉ์ Sendable ํ๋กํ ์ฝ์ ์ฐธ์กฐํ์ญ์์ค.
์ด๋ค ํ์ ์ ํญ์ sendableํฉ๋๋ค. ์๋ฅผ ๋ค์ด sendableํ ํ๋กํผํฐ๋ง ๊ฐ๋ ๊ตฌ์กฐ์ฒด๋, sendableํ ์ฐ๊ด๊ฐ๋ง ๊ฐ๋ ์ด๊ฑฐํ์ ๊ฒฝ์ฐ์ ๋๋ค. ์๋ฅผ ๋ค์ด:
struct TemperatureReading: Sendable {
var measurement: Int
}
extension TemperatureLogger {
func addReading(from reading: TemperatureReading) {
measurements.append(reading.measurement)
}
}
let logger = TemperatureLogger(label: "Tea kettle", measurement: 85)
let reading = TemperatureReading(measurement: 45)
await logger.addReading(from: reading)
TemperatureReading
์ sendableํ ํ๋กํผํฐ๋ง ๊ฐ๋ ๊ตฌ์กฐ์ฒด์ด๊ณ , public
์ด๋ @usableFromInline
์ผ๋ก ํ์๋์ง ์์๊ธฐ ๋๋ฌธ์, ์ด๊ฒ์ ์๋ฌต์ ์ผ๋ก sendableํฉ๋๋ค. ๋ค์์ ์๋ฌต์ ์ผ๋ก Sendable
ํ๋กํ ์ฝ ์ฑํ์ด ์ค์๋ ๊ตฌ์กฐ์ฒด์ ๋ฒ์ ์
๋๋ค:
struct TemperatureReading {
var measurement: Int
}