Swift Concurrency
Swift asynchronous and parallel code
1. Asynchronous and Parallel π©βπ»
Swift λ ꡬ쑰νλ λ°©λ²μΌλ‘ Asynchronous
, Parallel
μ½λ μμ±μ μ§μνλ€.
- Asynchronous code λ
Single Thread
λ‘ μλν΄ ν λ²μ νλμ μ½λλ§ μ€νμ΄ κ°λ₯νμ§λ§, μ½λλ₯Ό μ μ μ€λ¨ ν λ€μ μ¬κ°ν μ μλ μ½λ λΈλμΌλ‘, Fetching data λλ Parsing files μ κ°μlong-running background task
μ μμ² ν κΈ°λ€λ¦¬λ λμ UI Updateμ κ°μshort-term
μ μνν μ μλ€. - Parallel code λ
Multi Threads
λ‘ μλν΄ ν λ²μ μ½λμ μ¬λ¬ λΆλΆμ λμμ μ€ννλ€.
μ΄λ¬ν Concurrent code λ μ¬λ¬ μμ
μ λμμ μνν μ μλλ‘ νλ€. μ΄λ° μ½λλ₯Ό μμ±ν λλ μΈλΆ μμ€ν
μ κΈ°λ€λ¦¬λ μμ
μ μΌμ
μ€λ¨ν¨μΌλ‘μ¨ Memory-safe
ν λ°©μμΌλ‘ λ μ½κ² μμ±ν μ μλ€.
Asynchronous code μ Parallel code λ‘ μΈν scheduling
μ μ°μ± μΆκ°λ μ½λμ 볡μ‘μ± μ¦κ°λ₯Ό μλ°νλ€.
λμ Swift's language-level support
λ₯Ό μ§μνμ¬ Compiler κ° λ¬Έμ λ₯Ό μ°Ύμ μ μλλ‘ νλ€. μλ₯Ό λ€μ΄ Actor
λ₯Ό μ¬μ©ν΄
mutable state
μ μμ νκ² μ κ·Όν μ μλλ‘ νλ κ²κ³Ό κ°μ μλλ₯Ό νννλλ‘ ν΄ compile-time checking
μ κ°λ₯μΌ νλ€.
Concurrent code μ½λλ₯Ό μ¬μ©ν λ μ μν΄μΌ ν μ μ μ΄κ²μ΄ λ리거λ λ²κ·Έκ° μλ μ½λλ₯Ό λΉ λ₯΄κ³ μ ννκ² μλνλλ‘ ν΄μ€λ€λ 보μ₯μ΄ μλ€λ κ²μ΄λ€. μ€νλ € Concurrency λ μ½λμ λλ²κΉ μ μ΄λ ΅κ² ν΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μ΄λ ΅κ² λ§λ λ€. Asynchronous code μ Parallel code λ μ΄ λ‘μ§μ΄ νμν κ³³μμλ§ μ μ ν μ¬μ©ν΄μΌνλ€. Fetching data μ κ°μ΄ μΈλΆ μμΈμ μν μ§μ°μ κΈ°λ€λ¦¬λ κ²μ΄ μλ λ΄λΆμ μΌλ‘ λλ¦° μ½λλ μ½λμ λΉμ¦λμ€ λ‘μ§μ λ¬Έμ λ₯Ό μ°Ύμ ν΄κ²°ν΄μΌμ§ Concurrency λ₯Ό ν΅ν΄ ν΄κ²°νλ € ν΄μλ μ λλ€.
Swift μμ
Concurrency model
μ μ€λ λμ μ΅μλ¨μμ μλνμ§λ§ μ§μ μ μΌλ‘ μνΈμμ© νμ§ μλλ€. Swift μ Asynchronous Function μ μ€ν μ€μΈ μ€λ λλ₯Ό μ€λ¨ν μ μλ€. κ·Έλ¬λ©΄ 첫 λ²μ§Έ Asynchronous Function μ΄ μ€λ¨λ λμ λμΌ νλ‘κ·Έλ¨μ λ€λ₯Έ Asynchronous Function μ΄ ν΄λΉ μ€λ λμμ μ€νλ μ μλ€. λ°λΌμ Asynchronous Function μ΄ μ¬κ°λ λμ΄λ€ μ€λ λκ° κ·Έ ν¨μλ₯Ό μ€νν μ§
μ λν΄ μλ¬΄λ° λ³΄μ₯λ νμ§ μλλ€.
Swiftβs language support μμ΄λ Concurrent code λ₯Ό μμ±ν μ μμΌλ μ½λλ₯Ό μ½κΈ° μ΄λ ΅λ€. μλ μ½λλ
Swiftβs language support μμ΄ μμ±λ Concurrent code λ‘ κ°€λ¬λ¦¬μμ μ¬μ§ μ΄λ¦ λͺ©λ‘μ λ€μ΄λ‘λνκ³ , μ΄ λͺ©λ‘μμ λ€μ 첫 λ²μ§Έ
μ¬μ§μ λ€μ΄λ‘λν΄ μ¬μ©μμκ² λ³΄μ¬μ£Όλ μ½λλ€.
listPhotos(inGallery: "Summer Vacation") { photoNames in
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
downloadPhoto(named: name) { photo in
show(photo)
}
}
κ°λ¨ν μ½λμ΄μ§λ§ completion handler
κ° μ°μμ μΌλ‘ μμ±λμ΄μΌνλ―λ‘ Nested Closures
λ₯Ό μ¬μ©ν΄μΌνλ€. λ¬Έμ λ μ΄λ° μ½λκ° λ
볡μ‘ν΄μ§ κ²½μ° μ€μ²©μ λ λ§μ depth λ₯Ό κ°κ² λ κ²μ΄κ³ , μ΄λ μ½λλ₯Ό λ€λ£¨κΈ° μ΄λ ΅κ² λ§λ€ κ²μ΄λ€. μ΄λ TypeScript μμ μ€μ²©λ
Promise μ 볡μ‘ν μ½λμ async/await λ₯Ό μ¬μ©ν κ°λ
μ± μ’μ μ°μν μ½λλ₯Ό λΉκ΅ν΄λ³Έ μ μλ€λ©΄ μ΄λ€ μλ―ΈμΈμ§ μ½κ² μ΄ν΄κ° κ° κ²μ΄λ€.
Swiftβs language support λ₯Ό μ΄μ©ν Asynchronous Functions
λ₯Ό μ¬μ©νλ€λ κ²μ async/await
λ₯Ό μ¬μ©ν΄ μ½λλ₯Ό μμ±νλ
κ²μ μλ―Ένλ€.
Asynchronous Functions λ μ€ν μ€μΈ μ€λ λλ₯Ό μ€λ¨ν μ μλ€κ³ νλ€. Asynchronous Functions μμμ μ€νμ νλ¦μ΄ μ€λ¨λλ κ²½μ°λ λ€λ₯Έ λΉλκΈ° ν¨μλ₯Ό νΈμΆνλ κ²½μ°λ§ ν΄λΉλλ€. μ¦,
await
ν€μλλ₯Ό μ¬μ©ν΄ κΈ°λ€λ¦°λ€λ κ²μ λ€λ₯ΈλΉλκΈ° ν¨μμ λ°νμ κΈ°λ€λ¦°λ€λ μλ―Έ
μ΄λ€(λΉλκΈ° ν¨μ μμμ λ€λ₯Έ λΉλκΈ° ν¨μκ° μλ μΌλ° ν¨μλ μ½λ μμ await μ μ¬μ©νλ κ²μ μ무 μλ―Έκ° μλ€).
2. Asynchronous Functions π©βπ»
1. Asynchronous Syntax
Swift μμ Asynchronous Functions λ₯Ό μ μνλ λ°©λ²μ ν¨μλ₯Ό μ μν λ arrow(->)
μμ async
keyword λ₯Ό μμ±νλ κ²μΌλ‘
μ μλλ€.
func listPhotos(inGallery name: String) async -> [String] {
let result = // ... some asynchronous networking code ...
return result
}
Asynchronous Functions κ° μλ¬λ₯Ό throws
νλ κ²½μ° async throws
μμλ‘ keyword λ₯Ό μμ±νλ€.
func listPhotos(inGallery name: String) async throws -> [String] {
let result = // ... some asynchronous networking code ...
return result
}
2. async/await in TypeScript
μ°μ μ’ λ μ κ·Όμ±μ΄ μ½μ΄, async/await
λ₯Ό κ°μ₯ λ§μ΄ μ¬μ©ν΄λ΄€μλ§ν μ½λλ TypeScript μ Promise
κ° μλκΉ μκ°λλ€.
TypeScript μμ await λ₯Ό μ¬μ©νλ€λ κ²μ Promise κ°μ²΄λ₯Ό λ°ννλ ν¨μμ μ’
λ£λ₯Ό κΈ°λ€λ¦°λ€λ κ²μ μλ―Ένλ€. μ°μ
Asynchronous Functions λ₯Ό μ΄ν΄νκΈ° μν΄ TypeScript μμ λ₯Ό μ΄ν΄λ³΄μ.
κΈ°μ‘΄μ Promise κ°μ²΄λ₯Ό μ§μ μμ±νλ λ°©μκ³Ό λ¬λ¦¬ async/await λ₯Ό μ¬μ©νλ©΄ then..then..then..catch...finally
ννμ chaining λμ μ±κ³΅νμ κ²½μ° μ΄λ―Έ resolved μνμ κ°μ unwrapping ν΄ λ°ννκ³ , μλ¬λ catch λ₯Ό ν΅ν΄ μ²λ¦¬νλ€.
μ¦, μΌλ° μ½λλ₯Ό μμ±νλ― μ½λ©νλ©° try-catch
λ₯Ό ν΅ν΄ μ½λλ₯Ό μμ±ν μ μμΌλ©° μ½λμ μ€μ²©μ΄ μ€μ΄λ€κ³ μ€νμ νλ¦μ νμ
νκΈ° μ½λ€λ
μ₯μ μ κ°μ‘μλ€.
const asyncStr: () => Promise<string> =
async () => {
// throw Error('throw error!!')
return 'first'
}
- without async/await
const printOneTwo: () => void =
() => {
let str: Promise<string> = asyncStr() // Must be returned as (Promise, state is resolved) or (Promise, state is reject)
str.then((value: string) => console.log(value))
.catch((error: string) => console.error(error))
.finally(() => console.log('second'))
}
printOneTwo()
first
second
- with async/await
const printOneTwo: () => void =
async () => {
try {
let str: string = await asyncStr() // This returned as unwrapped, (string) or (Error)
console.log(str)
} catch (e) {
console.error(e)
}
console.log('second')
}
printOneTwo()
first
second
3. async/await in Swift
Swift μ async/await λ μ΄μ μ μ¬νλ€. await
λ₯Ό μ¬μ©νλ€λ κ²μ Task
λΌλ νλμ μμ
λ¨μ
κ° μ’
λ£λκ³
return
μ λ°νκ°μ κΈ°λ€λ¦°λ€λ κ²μ μλ―Ένλ€.
μ°Έκ³ λ‘ async
keyword μ throws
keyword λ₯Ό ν¨κΌ μΈ λλ async throws
μμλ‘ μμ±νμΌλ,
await
keyword μ try
keyword λ₯Ό ν¨κ» μΈ λλ 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)
await
μ€λ¨μ μ΄ μλlistPhotos(inGallery:)
ν¨μλ₯Ό νΈμΆ ν return μ΄ λ°νλ λκΉμ§ μ€νμ μ€λ¨νλ€.- μ΄ μ½λκ° μ€λ¨λ λμ long-running background task κ° νμν λμΌ νλ‘κ·Έλ¨μ λ€λ₯Έ Concurrent code κ° μ€νλλ€.
λ€λ₯Έ Concurrent code μμ λ€μ
await
μ€λ¨μ μ΄ νμλ μ½λκΉμ§ μ§ν ν μ€λ¨λκ±°λ λ μ΄μ μ€λ¨μ μ΄ μλ€λ©΄ ν΄λΉ ν¨μκ° μ’ λ£λ λκΉμ§ κ³μ μ§νλλ€. listPhotos(inGallery:)
κ° return λλ©° μ½λκ° μ¬μμλκ³ , λ³μ photoNames μ λ°νλ κ°μ assign νλ€.- λ€μ μ€λ¨μ μΈ
await
λ₯Ό λ§λκΈ° μ κΉμ§ *Synchronous code λ₯Ό μ§ν*νλ€. await
μ€λ¨μ μ΄ μλdownloadPhoto(named:)
ν¨μλ₯Ό νΈμΆ ν λ§μ°¬κ°μ§λ‘ return μ΄ λ°νλ λκΉμ§ μ€νμ μ€λ¨νλ€. β2.β μ λ§μ°¬κ°μ§λ‘ μ΄ μ½λκ° μ€λ¨λ λμ λ€λ₯Έ Concurrent code κ° μ€νλλ€.downloadPhoto(named:)
κ° return λλ©° μ½λκ° μ¬μμλκ³ , λ³μ photo μ λ°νλ κ°μ assign νλ€.- μ΄ν λ€λ₯Έ μ€λ¨μ μ΄ μμΌλ―λ‘ μ½λλ λ€μ Synchronous νκ² μ§νλμ΄
show(photo)
λ₯Ό νΈμΆν΄ μ¬μ§μ 보μ¬μ€λ€.
await
μ€λ¨μ μ μ½λμ μ€νμ μ€λ¨νκ³ ν΄λΉ μ€λ λμμ λ€λ₯Έ μ½λλ₯Ό μ€ννκΈ° λλ¬Έμ
μ΄λ₯Ό μ€λ λ μ보(yielding the thread)
λΌκ³ λΆλ₯Έλ€. μ΄κ²μ μ½λμ μ€νμ μ€λ¨ν μ μμ΄μΌνλ―λ‘,
μ±μ νΉμ μμΉμμλ§ Asynchronous Functions/Methods
λ₯Ό νΈμΆν μ μμΌλ©° κ·Έ νΉμ μμΉλ λ€μκ³Ό κ°λ€.
- Asynchronous Function/Method/Property μ
context
.
(async
keyword λ₯Ό μ¬μ©ν Closure λ₯Ό μκ°νλ©΄ λλ€) @main
μ΄ marked λ Structure/Class/Enumeration μstatic main() λ©μλμ context
- Unstructured Concurrency μ λμ¨ κ²κ³Ό κ°μ
Unstructured child task
4. Encapsulation the Code within an Asynchronous Code
λΉλκΈ° ν¨μ λ΄μμ await
keyword μΈ λ€λ₯Έ μ½λλ Synchronous λ‘ μλνλ©° μ½λλ₯Ό μμ°¨μ μΌλ‘ μ€ννλ€. νμ§λ§ μ΄κ² λ§μΌλ‘λ
μΆ©λΆνμ§ μμ μΌμ΄μ€κ° μ‘΄μ¬νλ€. λ€μ μ½λλ μ¬μ§μ Road Trip κ°€λ¬λ¦¬μ μΆκ°νκ³ , Summer Vacation κ°€λ¬λ¦¬μμ μμ νλ μ½λλ€.
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
κ° μΆκ°λλ€λ©΄ μ±μ λΆλ³μ± μλ°μ μΌμμ μ΄ μλλΌ μ€λ μκ° μ§μλ
μλ μκ²λλ€.
λ°λΌμ μ΄ μ½λ λ©μ΄λ¦¬(chunk)λ await
keyword κ° μΆκ°λλ©΄ μ λλ€λ κ²μ λͺ
μμ μΌλ‘ νννκ³ λΆλ¦¬μν€κΈ° μν΄ μ΄λ₯Ό 리ν©ν λ§ν΄
Synchronous Function/Closure
λ‘ λΆλ¦¬μμΌμΌνλ€.
func move(_ photoName: String, from source: String, to destination: String) {
add(photoName, to: destination)
remove(photoName, from: source)
}
// ...
let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
move(firstPhoto, from: "Summer Vacation", to: "Road Trip")
μ΄λ‘μ¨ move(_:from:to:)
ν¨μλ await
μ€λ¨μ μ μΆκ°ν κ²½μ° Swiftβs language-level support μ μν΄ compile-time error κ°
λ°μνλ―λ‘(async κ° λͺ
μλμ΄ μμ§ μμΌλ―λ‘ Synchronous Function μ΄λ€), Synchronous μλμ 보μ₯
λ°μ μ μλ€.
3. Asynchronous Sequences π©βπ»
μμμ λ³Έ listPhotos(inGallery:)
ν¨μλ Asynchronous Function
μΌλ‘ Collection μ΄ λͺ¨λ μ€λΉλ λκΉμ§ κΈ°λ€λ Έλ€ κ²°κ³Όλ₯Ό
ν λ²μ Array λ‘ return
νλ€.
κ·Έλ¦¬κ³ μ΄μ λ€λ₯Έ μ κ·Ό λ°©λ²μΌλ‘, Asynchronous Sequence
κ° μλ€. μ΄κ²μ Collection μ΄ λͺ¨λ μ€λΉλ λκΉμ§ κΈ°λ€λ¦¬μ§ μκ³ , μ€λΉ λλ
elements
λ₯Ό μ§μμ μΌλ‘ return νλ κ²μ΄λ€. μ¦, Collection μ΄ λͺ¨λ μ€λΉλ λκΉμ§ κΈ°λ€λ¦¬μ§ μκ³ Iterating
μ ν μ μλ€.
Iterating Over an Asynchronous Sequence
λ for-await-in
μ μ΄μ©ν΄ μ κ·Όνλ€.
import Foundation
let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
print(line)
}
μ μ½λμμ handle μ νμΌμ λͺ¨λ λ°μ΄ν°λ₯Ό ν λ²μ μ€λΉνμ§ μκ³ λΌμΈ νλλ₯Ό μ½μ ν iteration
μ΄ μ§νλ¨μ λ°λΌ μ€λ¨/μ¬κ°λ₯Ό λ°λ³΅νλ€.
Custom Types λ₯Ό λ§λ€ λ
iteration
μ νλλ‘ νκΈ° μν΄μλ λ€μ protocol μ μ±νμ΄ νμνλ€.
Sequence
protocol μ μ±ννλ©΄for-in
loop μ¬μ©μ΄ κ°λ₯νλ€.AsyncSequence
protocol μ μ±ννλ©΄for-await-in
loop μ¬μ©μ΄ κ°λ₯νλ€.
Swift μ
for-await-in
μ JavaScript μ for-await-ofμ λΉκ΅ν΄μ 보면 μ’μ κ² κ°λ€.
4. Calling Asynchronous Functions in Parallel π©βπ»
downloadPhoto(named:)
ν¨μλ Fetching data λ₯Ό νλ ν¨μλ‘ Asynchronous λ‘ μλνλ€.
λ°λΌμ await
μ€λ¨μ μ λ§λ μ½λκ° μ€λ¨λ λμ λ€λ₯Έ Concurrent code κ° μ€νλ μ μμ§λ§ λ€μκ³Ό κ°μ κ²½μ°λ λ€λ₯Έ Concurrent code κ°
μλ λμΌν Asynchronous Functions/Methods
μ μν΄μμΌλ―λ‘ λ§€λ² 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)
μ¬μ§μ λ©ν° λ€μ΄λ‘λλ₯Ό νλ κ²μ΄ λ ν¨μ¨μ μ΄λ€. λ°λΌμ μ 3κ°μ Asynchronous Function μ λ€μκ³Ό κ°μ΄ νλμ μ€λ¨μ μΌλ‘ λ¬Άμ΄ κ΄λ¦¬ν μ μλ€.
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)
Asynchronous Function μ΄ νΈμΆλ ν return μ΄ λ°νλλ μμ μ await
λ₯Ό κ±°λ κ²μ΄ μλλΌ,
λ³μμ λ°μ΄ν°κ° assign λλ κ²μ κΈ°λ€λ¦¬λλ‘ Asynchronous Property
λ₯Ό μ΄μ©νκ³ , μ΄λ₯Ό Array
μ λ΄μ await
λ₯Ό κ±Έμ΄μ€λ€.
μ΄λ κ² νλ©΄ κ°κ°μ downloadPhoto(named:)
ν¨μλ await
μ€λ¨μ μ΄ μκΈ° λλ¬Έμ λ€μ΄λ‘λλ₯Ό κΈ°λ€λ¦¬μ§ μκ³ λ€μ
downloadPhoto(named:)
λ₯Ό νΈμΆν΄ λμμ μ¬λ¬ κ°μ Asynchronous Function λ₯Ό νΈμΆνκ³ , μ΄ Asynchronous Property
κ° λ΄κΈ΄ Array
μ await
μ€λ¨μ μ΄ κ±Έλ € μκΈ° λλ¬Έμ Array μ λͺ¨λ κ°μ΄ assign λλ κ²μ κΈ°λ€λ¦° ν μ¬κ°λλ€.
Swift μ
await [func1, func2]
μ JavaScript μ Promise.all()μ λΉκ΅ν΄μ 보면 μ’μ κ² κ°λ€.
const [result1, result2] = await Promise.all([func1(), func2()])
5. Tasks and Task Groups π©βπ»
1. Structured Concurrency
Task
λ νλ‘κ·Έλ¨μ μΌλΆλ₯Ό Asynchronously νκ² μ€νν μ μλ μμ
μ λ¨μ(A unit of asynchronous work)
λ₯Ό λ§νλ©°,
λͺ¨λ Asynchronous code λ Task μ μΌλΆλ‘μ¨ μ€νλλ€. μμμ λ³Έ async let
syntax λ Task λ΄μ Child Task
λ₯Ό λ§λ€μ΄ λΈλ€.
Child Task κ° μ¬λ¬ κ°μΌ κ²½μ° μ΄λ₯Ό κ΄λ¦¬νκΈ° μν Task Group
μ μμ±νκ³ , μ΄ κ·Έλ£Ήμ Child Task λ₯Ό μΆκ°ν μ μλ€. μ΄λ₯Ό κ·Έλ£Ήν ν¨μΌλ‘μ¨
μ°μ μμμ μ·¨μλ₯Ό λ μ μ μ΄ν μ μμΌλ©°, λμ μΌλ‘ μμ
μ μλ₯Ό μμ±ν μ μλ€.
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 κ³Ό κ° Task λ parent-child
ꡬ쑰λ₯Ό κ°λλ€. λ°λΌμ Task Group λ΄ κ°κ°μ Child Task λ λμΌν Parent Task
λ₯Ό κ°λλ€.
κ·Έλ¦¬κ³ μ΄ κ°κ°μ Child Task λ λ λ€λ₯Έ Child Task λ₯Ό κ°μ§ μ μλ€. μ΄λ€μ Task Group μΌλ‘ λ¬ΆμΈ hierarchy
ꡬ쑰λ₯Ό
μ±ννκ³ μμΌλ©°, μ΄λ€ Task Group κ³Ό Tasks κ΄κ³λ₯Ό Structured Concurrency
λΌ νλ€.
Structured Concurrency λ μ νμ±μ λν μΌλΆ μ± μ(some responsibility for correctness)μ΄ μ¬μ©μμκ² μ£Όμ΄μ§μ§λ§ μ΄λ‘μ¨ Swift λ
Propagating Cancellation
μ μ²λ¦¬ν μ μμΌλ©°,compile-time error
λ₯Ό κ°μ§ν μ μλ€.
Task
μ λν μΆκ° μ 보λ Task λ₯Ό μ°Έκ³ νλ€.Task Group
μ λν μΆκ° μ 보λ TaskGroup μ μ°Έκ³ νλ€.
2. Unstructured Concurrency
Structured Concurrency μμ Tasks λ Task Group μ μν΄ λμΌν Parent Task
λ₯Ό κ°λ κ²κ³Ό λ¬λ¦¬
Unstructured Task
λ Parent Task
λ₯Ό κ°μ§ μλλ€. μ΄λ₯Ό Unstructured Concurrency
λΌ νλ€.
λ°λΌμ νλ‘κ·Έλ¨μ΄ μꡬνλλλ‘ Unstructured Task
λ₯Ό κ΄λ¦¬ν μ μλ μμ ν μ μ°μ±(complete flexibility)μ κ°λ λμ ,
μ νμ±μ λν μμ ν μ±
μ(completely responsibility for correctness)μ΄ μ¬μ©μμκ² μ£Όμ΄μ§λ€.
With great flexibility comes great responsibility
- νμ¬ Actor μμ μ€νλλ
Unstructured Task
λ₯Ό μμ±νκΈ° μν΄μλ Task.init(priority:operation:) initializer λ₯Ό νΈμΆν΄μΌνλ€. - νμ¬ Actor κ° μλ λΆλ¦¬λ μμ
(detached task)μΌλ‘
Unstructured Task
λ₯Ό μμ±νκΈ° μν΄μλ Task.detached(priority:operation:) class method λ₯Ό νΈμΆν΄μΌνλ€.
λ μμ μ λͺ¨λ κ²°κ³Όλ₯Ό κΈ°λ€λ¦¬κ±°λ(wait), μ·¨μνλ(cancel) μνΈ μμ©μ ν μ μλ
Task
λ₯Ό λ°ννλ€.
let newPhoto = // ... some photo data ...
let handle = Task {
return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}
let result = await handle.value
3. Task Cancellation
Swift μ Concurrency λ νλ μ·¨μ λͺ¨λΈ(Cooperative Cancellation Model)
μ μ¬μ©νλ€. κ°μ Tasks λ μ€ν μ€
μ μ ν μμ μ μ·¨μλμλμ§λ₯Ό νμΈ ν, μ μ ν λ°©μμΌλ‘ μ·¨μμ μλ΅νλ€.
Task Cancellation
μ μνμ€μΈ μμ
μ λ°λ₯΄λ©°, μΌλ°μ μΌλ‘ λ€μ μ€ νλλ₯Ό μλ―Ένλ€.
- Throwing an error like CancellationError
- Returning nil or an empty collection
- Returning the partially completed work
μμ μ΄ μ·¨μλμλμ§λ₯Ό νμΈνλ €λ©΄ λ€μ λ μ€ ν κ°μ§ λ°©λ²μ μ¬μ©νλ€.
- Task κ° μ·¨μλλ©΄
CancellationError
λ₯Ό throw νλ Type Method Task.checkCancellation λ₯Ό νΈμΆνλ€. - Type Property Task.isCancelled μ κ°μ νμΈνλ€.
κ·Έλ¦¬κ³ μ·¨μκ° νμΈλλ€λ©΄, νμ¬μ μ½λμμ μ·¨μλ₯Ό μ²λ¦¬(handle)ν΄μΌνλ€. μλ₯Ό λ€μ΄, downloadPhoto(named:)
μ΄ μ·¨μλ κ²½μ°,
1. λΆλΆ λ€μ΄λ‘λλ₯Ό μμ
νκ³ , 2. λ€νΈμν¬ μ μμ λ«μ
μ μ²λ¦¬ν΄μΌνλ€. κ·Έλ¦¬κ³ μ·¨μλ₯Ό μλμΌλ‘ μ ννλ €λ©΄
Instance Method Task.cancel() μ νΈμΆνλ€.
6. Actors π©βπ»
1. Actors in Swift
νλ‘κ·Έλ¨μ isolated, concurrent pieces
λ‘ λΆλ¦¬μν€κΈ° μν΄ Tasks λ₯Ό μ¬μ©ν μ μλ€. κΈ°λ³Έμ μΌλ‘ Tasks λ isolated
λμ΄ μμ΄
λμμ μ€ννλ κ²μ΄ μμ νμ§λ§ Tasks μ¬μ΄μ μ 보λ₯Ό 곡μ
ν νμκ° μλλ° μ΄λ Actors
λ₯Ό μ¬μ©νλ€. Actors λ Concurrent code κ°μ
μ 보λ₯Ό μμ νκ² κ³΅μ ν μ μκ² νλ€.
Actors λ Reference Types
λ‘ Classes μ λΉμ·νμ§λ§, Classes μ λ€λ₯΄κ² Actor λ λμμ νλμ Task λ§
mutable state
μ μ κ·Όμ νμ©νλ―λ‘, μ¬λ¬ Tasks κ° λμμ νλμ Actor instance μ μνΈμμ©ν΄λ μμ νλ€.
μ¦, Actors μ mutable state μ μ κ·Ό
νκΈ° μν΄μλ isolated λ Task λ¨μλ‘ μ κ·Ό
ν΄μΌνλ€. μ΄λ‘ μΈν΄ μ κ·Όνλ μ¦μ μμ²ν
κ°μ λ°ν λ°λλ€λ 보μ₯μ΄ μκΈ° λλ¬Έμ Actor μ Variable Properties λλ Methods μ μ κ·ΌνκΈ° μν΄μλ λ°λμ await
μ
μ¬μ©ν΄ μ κ·Όν΄μΌνλ€.
let
μΌλ‘ μ μΈν μμμ μ κ·Όν λλawait
keyword λ₯Ό λͺ μνμ§ μμλ λλ€.immutable
μ΄κΈ° λλ¬Έμ΄λ€.var
λ‘ μ μΈν λ³μλΌ νλλΌλ μ΄ λ³μλactor-isolated properties
μ΄λ―λ‘ μΈλΆcontext
μμ μμλ‘ κ°μ μμ νλ κ²μ λΆκ°λ₯νλ€.mutable
μ΄κΈ° λλ¬Έμ λ°λμawait
keyword λ₯Ό μ΄μ©ν΄ μ κ·Όν΄μΌνλ€.- λ©μλλ λ°νκ°μ΄ μλ λ©μλλΌ νλλΌλ μμμ μΌλ‘
Void
λΌλ νμ νΉμν κ°(()
λ‘ μ°μ¬μ§Empty Tuple
)μ λ°ννλ€.
κ·Έλ¦¬κ³ λ¨μν λ©μλμ νμ λ§μΌλ‘λ μ΄ λ©μλκ°Actor
μmutable state
μ μνΈμμ©μ νμ§ μλλ€λ κ²μ 보μ₯ν μ μλ€. μλ₯Ό λ€μ΄ λ°λΌμDictionaries
μ κ°μ μ‘°νμ νμOptional
λ‘ λ°ννλ κ²μ²λΌActor
μ λͺ¨λ λ©μλλ νΈμΆμ νμawait
keyword λ₯Ό μ΄μ©ν΄ μ κ·Όν΄μΌνλ€.
λ€μ μμ λ μ¨λλ₯Ό κΈ°λ‘νλ 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
}
}
Actors λ actor
keyword λ₯Ό μ΄μ©ν΄ μ μνλ€. μ TemperatureLogger Actor λ 3κ°μ properties λ₯Ό κ°μ§κ³ μμΌλ©°,
κ·Έ μ€ max λ var
λ‘ μ μΈλμμΌλ©°, private(set)
modifier μ μν΄ get μ internal
, set μ private
μ
Access Level μ κ°λλ€.
2. Actor Isolation
Swift λ Actor μ local state
μ μ κ·Όν μ μλ κ²μ Actor μ context
λ‘ μ νν¨μΌλ‘μ¨ Asynchronous work
μμλ
mutable state
λ₯Ό μμ νκ² κ³΅μ ν μ μμμ 보μ₯(guarantee)νλ€.
μ μ νμ μμΈν μ΄ν΄λ³΄κ² μ§λ§, μ΄ λ³΄μ₯μ±μΌλ‘ Actor μ let
properties λ₯Ό μ μΈν λͺ¨λ var
properties μ Methods
λ
λ°λμ await
keyword λ₯Ό μ΄μ©ν΄ μ κ·Όν΄μΌνλ©°, κ·Έλ μ§ μμΌλ©΄ μλ¬κ° λ°μνλ€.
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max) // 25
Swift μ μ΄λ° 보μ₯μ±μ Actor Isolation
μ΄λΌ νλ€.
3. Class with private properties
Actor κ° Class μ μ΄λ»κ² λ€λ₯Έμ§ μμ보기 μν΄ μμ λ€μκ³Ό κ°μ΄ TemperatureLogger λ₯Ό Class λ₯Ό λ§λ€μ΄ Actor μ λΉκ΅ν΄λ³΄λλ‘νμ.
class TemperatureLogger {
let label: String
var measurements: [Int]
private var max: Int
init(label: String, measurement: Int) {
self.label = label
self.measurements = [measurement]
self.max = measurement
}
func getMax() -> Int {
max
}
}
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(logger.label) // Outdoors
print(logger.max) // error: 'max' is inaccessible due to 'private' protection level
print(logger.getMax()) // 25
private
modifier μ μν΄ get κ³Ό set λͺ¨λ private
μ Access Level μ κ°κΈ° λλ¬Έμ μΈλΆ context μμ
μ§μ μ κ·Όμ΄ λΆκ°λ₯νλ€.
4. Class with private(set) properties
μ΄μ max μ modifier λ₯Ό private(set)
μΌλ‘ λ°κΏλ³΄μ.
class 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
}
func getMax() -> Int {
max
}
}
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(logger.label) // Outdoors
print(logger.max) // 25
print(logger.getMax()) // 25
μ΄μ max property λ private(set)
μ΄λ―λ‘ get μ internal
, set μ private
μ Access Level μ
κ°κΈ° λλ¬Έμ getter λ©μλ μμ΄ μΈλΆμμ μ κ·Όμ΄ κ°λ₯νλ€.
5. Actor with private property
κ·Έλ λ€λ©΄ Actor μμμ private
μ μ΄λ»κ² μλν κΉ?
actor TemperatureLogger {
let label: String
var measurements: [Int]
private var max: Int
init(label: String, measurement: Int) {
self.label = label
self.measurements = [measurement]
self.max = measurement
}
func getMax() -> Int {
max
}
func greeting(name: String) {
print("Hello~ \(name)")
}
}
Task {
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(logger.label) // Outdoors
print(logger.max) // error: 'max' is inaccessible due to 'private' protection level
print(await logger.getMax()) // 25
await logger.greeting(name: "Actor Methods") // Hello~ Actor Methods
}
- logger.label :
let
μΌλ‘ μ μΈλμ΄ μλ€λ©΄immutable
μ΄λ―λ‘ Class μ λ§μ°¬κ°μ§λ‘ μΈλΆcontext
μμ μμ λ‘κ² μ κ·Όμ΄ κ°λ₯νλ€. - logger.max :
get
κ³Όset
λͺ¨λprivate
μ Access Level μ κ°κΈ° λλ¬Έμ μΈλΆ context μμ μ§μ μ κ·Όμ΄ λΆκ°λ₯νλ€. - logger.getMax() :
getMax()
λ©μλλ Actor μ λ©μλμ΄λ―λ‘await
μ μ΄μ©ν΄ μ κ·Όν΄μΌνλ€. - logger.greeting(name:) : μ΄λ ν
mutable state
μ μνΈμμ©μ νμ§ μλλ€. νμ§λ§greeting(name:)
λ©μλ μμ Actor μ λ©μλμ΄λ―λ‘await
μ μ΄μ©ν΄ μ κ·Όν΄μΌνλ€.
6. Actor with private(set) property
μ΄μ μλλλ‘ λμμ private(set)
μΌλ‘ λ°κΏλ³΄μ.
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
}
func getMax() -> Int {
max
}
}
Task {
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.label) // Outdoors, No 'async' operations occur within 'await' expression
print(logger.label) // Outdoors
logger.measurements[0] = 0 // error: actor-isolated property 'measurements' can not be mutated from a non-isolated context
print(logger.max) // error: expression is 'async' but is not marked with 'await'
print("1. \(await logger.max)") // 1. 25
await print("2. \(logger.max)") // 2. 25
print("3. \(await logger.getMax())") // 3. 25
await print("4. \(logger.getMax())") // 4. 25
}
μ΄λ²μ λͺ¨λ μΌμ΄μ€μ λν΄ μ΄ν΄λ³΄λ©° Actor μ
mutable state
μimmutable
μ μ°¨μ΄λ ν¨κ» μ΄ν΄λ³Έλ€.
- await logger.label :
let
μΌλ‘ μ μΈν μμμ΄λ―λ‘ λΉλκΈ°λ‘ μλνμ§ μλλ€. λ°λΌμ μ μ μλνμ§λ§await
λ 무μλκ³ μ»΄νμΌλ¬λawait
μ μ§μΈ κ²μ μꡬνλ€. - logger.label :
let
μΌλ‘ μ μΈλμ΄immutable
μ΄λ―λ‘await
μμ΄λ Actor μ κ°μ μ μμ μΌλ‘ μ κ·Όν μ μλ€.
(λ¨, Actor μ체μ λν μ κ·Όμ λ°λμ Task μμμ μ΄λ£¨μ΄μ ΈμΌνλ€) - logger.measurements[0] = 0 :
var
λ‘ μ μΈλμμ§λ§ measurements λactor-isolated property
μ΄λ―λ‘ Actor μ context μΈλΆμμ μμ μ΄ λΆκ°λ₯νλ€. - logger.max :
private(set)
μ΄λ―λ‘ get μinternal
, set μprivate
μ Access Level μ κ°κΈ° λλ¬Έμ Class μ λ§μ°¬κ°μ§λ‘ getter λ©μλ μμ΄ μΈλΆμμ μ κ·Όμ΄ κ°λ₯νλ€. νμ§λ§var
μ΄κΈ° λλ¬Έμawait
μμ΄ μ κ·Όνλ κ²μ λΆκ°λ₯νλ€. - logger.max / logger.getMax() :
print(_:)
argument μawait
μ κ±Έλ ,print(_:)
νΈμΆμawait
μ κ±Έλ λͺ¨λ μ μμ μΌλ‘ μλνλ€.
7. Extensions of 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
}
}
extension TemperatureLogger {
func update(with measurement: Int) {
measurements.append(measurement)
if measurement > max {
max = measurement
}
}
}
Swift μ Extensions λ extension
keyword λ₯Ό μ΄μ©ν΄ Class, Structure,
Enumeration, Protocol μ νμ₯νλ€. μ΄λ Objective-C μ Categories μ μ μ¬νλ€.
μ¦, update(with:)
λ©μλλ μ΄λ―Έ Actor λ΄λΆμ μλ κ²μ΄κΈ° λλ¬Έμ Actor μ context
μ ν¬ν¨λλ―λ‘ await
keyword
μμ΄ mutable state
μ μ κ·Όν μ μλ€.
7. Sendable Types π©βπ»
1. Concurrency Domain
Tasks μ Actors λ νλ‘κ·Έλ¨μ μΌλΆλ₯Ό μ‘°κ°μΌλ‘ λΆλ¦¬μμΌ Concurrent code κ° μμ νλλ‘ λ§λ λ€. Task λλ Actor instance μ
λ΄λΆμ var
λ‘ μ μΈλ mutable state
λ₯Ό ν¬ν¨νλ κ²½μ°κ° μλλ° μ΄λ₯Ό Concurrency domain
μ΄λΌ νλ€. μ΄λ κ² mutable state λ₯Ό
ν¬ν¨νμ§λ§ λμ μ κ·Ό(overlapping access)μ λν΄ λ³΄νΈλμ§ μλ κ²½μ°λ Concurrency domain κ°μ 곡μ λ μ μλ€.
2. Sendable Protocol
Concurrency domain κ°μ 곡μ λ μ μλ νμ
μ Sendable Types
λΌ νλ€. Sendable Types λ Actor μ λ©μλλ₯Ό νΈμΆν λ
arguments λ‘ μ λ¬
λκ±°λ Task μ κ²°κ³Όλ‘μ¨ λ°ν
λ μ μλ€.
Value Types λ μΈμ λ μμ ν 곡μ κ° κ°λ₯νλ€. λ°λΌμ Concurrency domain κ°μλ μμ νκ² κ³΅μ
ν μ μλ€.
λ°λ©΄, Reference Types λ Concurrency domain κ°μ μ λ¬νκΈ°μ μμ νμ§ μλ€
. Class κ° mutable properties λ₯Ό ν¬ν¨νκ³ ,
μμ°¨μ μ κ·Ό(serialize access)μ νμ§ μλλ€λ©΄
, μλ‘ λ€λ₯Έ Tasks κ°μ Class μ instance λ₯Ό μ λ¬ν λ μμΈ‘ λΆκ°λ₯νκ³
μλͺ»λ κ²°κ³Όλ₯Ό μ λ¬ν μ μλ€(무λΆλ³ν μμλ‘ μ κ·Όν κ²½μ° Reference Types μ κ°μ΄ μλν μμ μ΄ μλλ°λ λΆκ΅¬νκ³ λ³κ²½λ μ μλ€).
μ΄ λ¬Έμ λ₯Ό ν΄κ²·νκΈ° μν΄ μ°λ¦¬λ Sendable Protocol μ μ€μνλλ‘(conformance) μ μΈ
ν΄ Sendable Types
λ‘ λ§λ€ μ μλ€.
Sendable Protocol μ μ½λμ μΈ μꡬμ¬ν(code requirements)μ μμ§λ§,
Swift κ° κ°μ νλ μλ―Έλ‘ μ μΈ μꡬμ¬ν(semantic requirements)μ΄ μλ€.
Sendable μ μ€λͺ μ λ€μ μ½μ΄λ³΄μ.
Sendable Types μ κ°μ νλμ Concurrency domain μμ λ€λ₯Έ Concurrency domain μΌλ‘ μμ νκ² λ³΄λΌ μ μλ€. μλ₯Ό λ€μ΄, Sendable Values λ Actor μ λ©μλλ₯Ό νΈμΆν λ arguments λ‘ μ λ¬λ μ μλ€. λ€μμ λͺ¨λ Sendable λ‘ νμ κ°λ₯νλ€(marked as sendable).
- Value Types
- Reference types with no mutable storage
- Reference types that internally manage access to their state
- Functions and closures (by marking them with
@Sendable
)
μμμ μ΄λ―Έ μ΄ν΄λ³΄μλ μ΄ μ΄ νλ‘ν μ½μ required methods λ required properties μ κ°μ μꡬμ¬νμ μμ§λ§, `compile-time μ κ°μ λλ μλ―Έλ‘ μ μΈ μꡬμ¬ν(semantic requirements)*μ΄ μλ€. κ·Έλ¦¬κ³ Sendableμ λ°λμ Typeμ΄ μ μΈλ νμΌ λ΄μμ μ μΈλμ΄μΌνλ€. μ΄λ¬ν μꡬμ¬νμ λν΄μλ μλ λ²νΈμ μ΄μ΄μ μ€λͺ νλ€.
Compiler μ κ°μ μ± μμ΄ Sendable μ μ μΈνλ €λ©΄ Sendable
protocol λμ @unchecked Sendable
protocol μ μ±ννλ€.
μ΄ κ²½μ° μ νμ±μ λν μ±
μμ΄ μ¬μ©μμκ² μμΌλ©°, μ¬μ©μλ lock
λλ queue
λ₯Ό μ΄μ©ν΄ νμ
μ μνμ λν λͺ¨λ μ κ·Όμ 보νΈν΄μΌνλ€.
λν μ΄ Unchecked conformance to Sendable
μ Sendable μ΄ λ°λμ Type μ΄ μ μΈλ νμΌ λ΄μμ μ μΈλμ΄μΌ νλ€λ κ·μΉ μμ
λ°λ₯΄μ§ μλλ€.
3. Sendable Structures and Enumerations
Structures μ Enumerations κ° Sendable Protocol μ λ§μ‘±μν€κΈ° μν΄ Sendable Members
μ Associated Values
λ§
κ°μ ΈμΌνλ€.
μΌλΆ μΌμ΄μ€μ κ²½μ° μμμ μΌλ‘ Sendable μ λ°λ₯΄λλ° κ·Έκ²μ λ€μκ³Ό κ°λ€.
Frozen
structures and enumerations- Structures and enumerations that
arenβt public
andarenβt marked @usableFromInline
.
μ΄ μΈ κ²½μ°λ Sendable μ λν μ ν©μ±μ λͺ μμ μΌλ‘ μ μΈν΄μΌνλ€.
Structures κ° nonsendable stored properties
λ₯Ό κ°μ§κ³ μκ±°λ, Enumerations κ° nonsendable associated values
λ₯Ό
κ°μ§κ³ μλ€λ©΄ Sendable
μ ν©μ±μ λ°λ₯Ό μ μλ€. λ°λΌμ μ΄ κ²½μ° μμμ μ€λͺ
νλ―μ΄ @unchecked Sendable
λ₯Ό νμν΄
compile-time error λ₯Ό λΉνμ±ν ν ν μ¬μ©μκ° μ§μ ν΄λΉ
Types κ° Sendable Protocol μ μλ―Έλ‘ μ μΈ μꡬμ¬ν(semantic requirements)μ λ§μ‘±νλμ§ κ²μ¦
ν΄μΌνλ€.
4. Sendable Actors
Actors λ λͺ¨λ mutable state μ μμ°¨μ μΈ μ κ·Όλ§ νμ©νκΈ° λλ¬Έμ μμμ μΌλ‘ Sendable μ λ§μ‘±νλ€.
5. Sendable Classes
Classes κ° Sendable Protocol μ λ°λ₯΄κΈ° μν΄μλ λ€μμ λ§μ‘±ν΄μΌνλ€.
- Be marked final
- Contain only stored properties that are immutable and sendable
- Have no superclass or have NSObject as the superclass
μλ₯Ό λ€λ©΄ λ€μκ³Ό κ°μ Classes λ Swift μ μν΄ Sendable Protocol μ μ±νν΄ μ ν©μ±μ λ°λ₯΄λλ‘ ν μ μλ€.
final class Abc: Sendable {
let x: String
init(x: String) {
self.x = x
}
}
1 ) @MainActor
κ° νμλ Classes
λ μμμ μΌλ‘ Sendable
μ λ§μ‘±νλ€.
Main Actor
λ μμ μ state μ λν λͺ¨λ μ κ·Όμ μ‘°μ νκΈ° λλ¬Έμ μμμ μΌλ‘ Sendable μ λ§μ‘±νλ©°, μ΄ Classes λ
mutable
νκ³ nonsendable
ν Stored Properties λ₯Ό μ μ₯ν μ μλ€.
2 ) Verify conform to sendable protocol manually
μ μ¬νμ λ°λ₯΄μ§ μλ Classes λ @unchecked Sendable
μ νμνκ³ μ¬μ©μκ° μ ν©μ±μ λ§μ‘±νλμ§ νμΈνλ€.
class Abc: @unchecked Sendable {
let x: String
init(x: String) { self.x = x }
}
@unchecked Sendable
λ₯Ό νμν΄ compile-time error λ₯Ό λΉνμ±ν ν ν μ¬μ©μκ° μ§μ ν΄λΉTypes κ° Sendable Protocol μ μλ―Έλ‘ μ μΈ μꡬμ¬ν(semantic requirements)μ λ§μ‘±νλμ§ κ²μ¦
ν΄μΌνλ€.
6. Sendable Functions and Closures
Sendable Protocol μ λ°λ₯΄κ² νλ λμ @Sendable
attribute μ¬μ©ν΄ Sendable Functions
λλ Sendable Closures
μ λνλΌ μ μλ€.
λΉμ°ν μ λ¬λλ Functions λλ Closures μ λͺ¨λ κ°
μ Sendable μ λ§μ‘±ν΄μΌνλ€. μΆκ°λ‘ Closures
λ μ€μ§ Value
μΊ‘μ²λ§ μ¬μ©ν΄μΌνλ©°, κ·Έ κ°μ λ°λμ Sendable Type
μ΄μ΄μΌ νλ€.
Task.detached(priority:operation:)
νΈμΆκ³Ό κ°μ΄ Sendable Closures λ₯Ό μμνλ context μμ μꡬμ¬νμ λ§μ‘±νλ ν΄λ‘μ λ
μμμ μΌλ‘ Sendable μ λ§μ‘±νλ€.
λ€μκ³Ό κ°μ΄ Type Annotation
μ μΌλΆλ‘ @Sendable
μ νμνκ±°λ parameters μ μμ @Sendable
μ νμν¨μΌλ‘ λͺ
μμ μΌλ‘
Sendable μ λ§μ‘±ν¨μ λνλΌ μ μλ€.
let sendableClosure = { @Sendable (number: Int) -> String in
if number > 12 {
return "More than a dozen."
} else {
return "Less than a dozen"
}
}
7. Sendable Tuples
Sendable protocol μ λ§μ‘±νκΈ° μν΄μλ Tuples
μ λͺ¨λ elements κ° Sendable μ λ§μ‘±ν΄μΌνλ©°, μ‘°κ±΄μ΄ λ§μ‘±λλ©΄
Tuples μμ μμμ μΌλ‘ Sendable μ λ§μ‘±
νλ€.
8. Sendable Metatypes
Int.Type
κ³Ό κ°μ Metatypes
λ μμμ μΌλ‘ Sendable
μ λ§μ‘±νλ€.
λ€μμ Int
κ° μ΄λ»κ² Sendable protocol μ λ§μ‘±νλμ§λ₯Ό 보μ¬μ€λ€.
extension Int: Sendable {}
λ°λΌμ λ€μκ³Ό κ°μ Structure λ μμμ μΌλ‘ Sendable μ λ§μ‘±νλ€.
struct Abc {
var xyz: Int
}
λ§μ½ Genenric Type
μ΄ Sendable μ λ§μ‘±νμ§ μμ κ²½μ° λ€μκ³Ό κ°μ΄ μ ν©μ±μ λ°λ₯΄λλ‘ ν μ μλ€.
struct Box<Val: Sendable> {
var abc: Val
}
Reference
- βConcurrency.β The Swift Programming Language Swift 5.7. accessed Jan. 05, 2023, Swift Docs Chapter 17 - Concurrency.
- βfor awaitβ¦of.β MDN Web Docs. Dec. 14, 2022, accessed Jan. 10, 2023, MDN - for awaitβ¦of.
- βPromise.all().β MDN Web Docs. Dec. 14, 2022, accessed Jan. 10, 2023, MDN - Promise.all().
- βTask.β Apple Developer Documentation. accessed Jan. 11, 2023, Apple Developer Documentation - Swift/Swift Standard Library/Concurrency/Task.
- βTaskGroup.β Apple Developer Documentation. accessed Jan. 11, 2023, Apple Developer Documentation - Swift/Swift Standard Library/Concurrency/TaskGroup.
- βcheckCancellation().β Apple Developer Documentation. accessed Jan. 11, 2023, Apple Developer Documentation - Swift/Swift Standard Library/../checkCancellation().
- βisCancelled.β Apple Developer Documentation. accessed Jan. 11, 2023, Apple Developer Documentation - Swift/Swift Standard Library/../isCancelled.
- βcancel().β Apple Developer Documentation. accessed Jan. 11, 2023, Apple Developer Documentation - Swift/Swift Standard Library/../cancel().
- βSendable.β Apple Developer Documentation. accessed Jan. 13, 2023, Apple Developer Documentation - Swift/Swift Standard Library/Sendable.
- βSendable and @Sendable in Swift.β Mobikul, Jul. 01, 2022, Mobikul - Sendable and @Sendable in Swift.