-
Notifications
You must be signed in to change notification settings - Fork 0
Structured Concurrency (구조적 동시성) #7
Copy link
Copy link
Open
Labels
Description
반복문 내부의 async 함수
func fetchImages(urls: [String]) async -> [UIImage] {
var images: [UIImage] = []
for url in urls {
let image = await fetchImage(url) // 각 반복마다 기다림
images.append(image)
}
return images
}-
for + await조합은 순차 실행 -> 한 이미지 다운로드가 끝나야 다음 반복으로 진행- 비동기지만, 동시에 실행되는 게 아니라 순서대로 실행됨
-
Concurrency의
await은 특정 스레드에서만 실행되는 게 아님-
await에서 Task가 멈췄다가 재개될 때는 다른 스레드에서 이어질 수 있음
-
특정 스레드를 점유하지 않고 필요 시 CPU를 양보
-
Thread 1 ───────────────────────────────────────────────
Task
Thread 2 task1 실행 ---- await ──┐
│ (중단)
Thread 3 └────── task2 실행 ---- await ──┐
│ (중단)
Thread 4 └────── task3 실행 ---- await ── 끝
구조적 동시성
-
부모 Task와 자식 Task 간 명확한 계층 관계 형성
-
자식 Task는 동시로 실행되고, 모두 완료되어야 부모가 종료
부모 Task
├─ 자식 Task 1 ─ 완료
├─ 자식 Task 2 ─ 완료
└─ 자식 Task 3 ─ 완료
↓
모든 자식 종료 → 부모 Task 종료
-
Concurrency의 구조적 동시성
- async let (암시적 하위 작업 생성)
- TaskGroup (동적/확장성 있는 하위 작업 관리)
-
메타데이터 상속
- 자식 작업은 부모 작업의
우선순위,실행 액터,Task-Local 변수를 상속
- 자식 작업은 부모 작업의
-
취소 전파 (협력적 취소)
- 부모가 취소되면 자식도 취소 전파
- 단, Task는 즉시 종료되지 않고 “취소 상태”만 전달됨
async let
-
async let으로 여러 비동기 작업을 동시에 실행 시작 -
필요 시점에
await으로 결과 수집 -
async let으로 만든 값은 해당 스코프 안에서await로 소비 필요
Task {
// 동시에 실행 시작
async let image1 = fetchImage(num: 1)
async let image2 = fetchImage(num: 2)
async let image3 = fetchImage(num: 3)
async let image4 = fetchImage(num: 4)
// 결과를 기다릴 때 중단
let result1 = try await image1
let result2 = try await image2
let result3 = try await image3
let result4 = try await image4
imageArray.append(contentsOf: [result1, result2, result3, result4])
}- 아래와 같이 작성해도 무방
// 튜플로 묶기
let (r1, r2, r3, r4) = try await (image1, image2, image3, image4)
// 옵셔널 처리 포함
let (r1, r2, r3, r4) = await (try? image1, try image2, try image3, try image4)
// inline await
let results = (try await image1,
try await image2,
try await image3,
try await image4)TaskGroup
-
동적/대규모 동시 실행에 적합
-
모든 작업이 완료될 때까지 자동으로 기다려줌
-
반복문 안에서 Task를 추가하고, 완료되는 순서대로 결과를 받아올 수 있음
- -> 입력 순서와 수집 순서는 다를 수 있음
func fetchImages(urls: [String]) async -> [UIImage] {
await withTaskGroup(of: UIImage?.self) { group in
for url in urls {
// 반복문 안에서 원하는 만큼 Task를 추가
group.addTask { await fetchImage(url) }
}
var results: [UIImage] = []
// 작업이 끝나는 순서대로 결과를 수집
for await image in group {
if let image { results.append(image) }
}
// 그룹 전체 결과 반환
return results
}
}DispatchGroup vs Structured Concurrency
DispatchGroup (GCD)
-
enter/leave 수동 관리 → 누락/중복 시 버그 위험
-
취소/에러 전파 없음 → 직접 구현 필요
-
결과 흐름이 콜백 기반이라 코드가 분산됨
Structured Concurrency (async let, TaskGroup)
-
부모-자식 관계로 자동 관리
-
모든 자식 Task가 끝나야 부모 Task 종료
-
취소·에러 자동 전파, 코드 흐름이 직관적
Reactions are currently unavailable