Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- claen architecture
- 타임라인 포맷팅
- identifiable
- swift dashed line
- swift 백준
- swift bottomsheet
- uikit toast
- RxSwift
- button configuration
- paragraph style
- task cancellation
- swift concurrency
- coordinator
- custom ui
- BFS
- swift 점선
- custombottomsheet
- swift navigationcontroller
- UIKit
- domain data
- tusit font 추가 방법
- custom navigation bar
- SWIFT
- DP
- task cancel
- reactorkit
- swift custom ui
- Tuist
- rxdatasources
- traits
Archives
- Today
- Total
김경록의 앱 개발 여정
[Swift Concurrency] 구조적 동시성의 취소(feat: 명시,암시적 취소전파) 본문
✅ 구조적 동시성과 작업 취소
구조적 동시성이란?
- 부모 Task가 종료되기 전까지, 그 아래에서 생성된 자식 Task들도 모두 종료되어야 하는 규칙
- Swift의 async let, withTaskGroup 이 대표적인 구조적 동시성 도구
- 취소는 위에서 아래로 전파됨 (부모 → 자식)
즉, 부모가 취소되면, 구조적으로 연결된 자식들도 자동으로 취소됨
구조적 동시성에 관한 이전 글 ) https://roks-apps.tistory.com/76
✅ async let의 작업 취소
특징
- async let 은 선언된 순간 비동기 작업을 시작하고, 자동으로 취소 전파 대상이 됨
- await 하기 전에 부모 Task가 취소되면, async let 작업도 취소됨
- 특별히 .cancel() 하지 않아도 자동으로 정리(cleanup) 됨
예시
func loadData() async {
async let user = fetchUser()
async let posts = fetchPosts()
do {
let result = try await (user, posts)
print("결과: \(result)")
} catch is CancellationError {
print("작업이 취소되었습니다.")
}
}
- 위에서 loadData() 가 취소되면 fetchUser() 와 fetchPosts() 도 같이 취소됨
- try await 하는 시점에서 취소되었으면, CancellationError 가 던져짐
✅ TaskGroup의 작업 취소
특징
- withTaskGroup 또는 withThrowingTaskGroup 내에서 만든 Task들은 부모 TaskGroup에 소속
- 부모가 cancelAll() 호출하면, 그 시점 이후 추가된/미완료된 작업들이 취소됨
- 작업 내부에서는 Task.isCancelled 이나 Task.checkCancellation()로 반응하도록 구현해야 함
예시
- group.cancelAll()은 이미 끝난 작업에는 영향 없음
- 각 작업 내부에서 직접적으로 취소에 반응하도록 처리해야 함 (Task.isCancelled 등 사용)
func processTasks() async {
await withTaskGroup(of: Void.self) {
group in for i in 0..<5 {
group.addTask {
try? await Task.sleep(nanoseconds: UInt64(i) * 500_000_000)
if Task.isCancelled {
print("Task \(i) 취소됨")
return
}
print("Task \(i) 완료")
}
} // 1초 후 취소 try? await Task.sleep(nanoseconds: 1_000_000_000) group.cancelAll() // -> 아직 끝나지 않은 Task 들에 취소 요청 }
}
}
✅ 비교 정리
항목async letTaskGroup
구조적 동시성 | ✅ | ✅ |
취소 전파 | 부모 취소 시 자동 전파 | cancelAll() 호출로 수동 전파 |
자식 작업 취소 처리 | 자동 | 수동 (isCancelled, checkCancellation) |
예외 전파 | 가능 (자동 throw) | 가능 (withThrowingTaskGroup 사용 시) |
결과 수집 | 튜플 등으로 간단하게 | 루프나 배열로 직접 처리 |
🧠 요약
- async let: 간결, 취소 자동 처리, 에러 자동 전파
- TaskGroup: 유연, 작업 수동 취소 가능, 복잡한 컨트롤에 적합
- 둘 다 부모 취소 시 자식도 함께 취소됨 → 결국 이게 구조적 동시성의 핵심
✅ 명시적 취소 전파 (Explicit Cancellation Propagation)
뜻
- 개발자가 직접 코드로 취소를 요청하거나
직접 자식 작업에게 신호를 보내는 방식
예시
1. Task.cancel(), group.cancelAll() 같은 메서드 호출
let task = Task { // 작업 내용 } task.cancel() // 👈 명시적으로 취소 전파
2. TaskGroup 내에서 수동으로 취소 요청
swift
복사편집
await withTaskGroup(of: Void.self) { group in
group.addTask { await someWork() }
group.cancelAll() // 👈 명시적 취소 요청
}
3. 내부 로직에서 명시적으로 Task.isCancelled 체크
if Task.isCancelled {
// 👈 명시적으로 체크하고 정리
return
}
✅ 암시적 취소 전파 (Implicit Cancellation Propagation)
뜻
- Swift의 구조적 동시성에 의해 자동으로 일어나는 취소 전파
- 부모 Task가 취소되면, 구조 내 자식 Task들도 자동으로 취소 요청을 받음
예시
1. async let 이 포함된 부모 Task가 취소되면
func parentTask() async {
async let user = fetchUser()
async let posts = fetchPosts()
// 이 Task 자체가 취소되면 user, posts 도 암시적으로 취소됨
}
2. withTaskGroup 안의 작업들도 부모 Task가 취소되면 자동 취소
func parent() async {
await withTaskGroup(of: Void.self) { group in
group.addTask {
await longRunningWork()
}
// 이 함수 전체가 취소되면, group의 자식 작업도 암시적으로 취소됨
}
}
3. try await 로 취소에 대응하는 시스템 API 사용 시
try await URLSession.shared.data(from: url)
// Task가 취소되면 암시적으로 이 API도 중단됨
🧠 비교 정리
구분 | 명시적 취소 전파 | 암시적 취소 전파 |
정의 | 개발자가 직접 .cancel(), cancelAll() 등을 호출 | 구조적 동시성 또는 시스템 동작에 의해 자동 발생 |
예시 | task.cancel(), group.cancelAll() | 부모 Task 취소 → 자식 Task 자동 취소 |
Task 내부 대응 | 보통 Task.isCancelled, checkCancellation() 사용 | 대부분 CancellationError throw 혹은 시스템 API 취소 |
코드 관여도 | 높음 (수동 처리 필요) | 낮음 (자동 전파) |
유용한 상황 | 조건부 취소, 복잡한 제어 필요 시 | 단순 구조, 자동 관리 시 |
'TIL' 카테고리의 다른 글
[Swift Concurrency] Task의 취소 (0) | 2025.04.18 |
---|---|
[Swift Concurrency] Structured Concurrency 구조적 동시성 (0) | 2025.04.15 |
[Swift] Identifiable (0) | 2025.03.28 |
[RxSwift] Single<Void> 와 Completable (0) | 2025.03.13 |
[Clean Architecture] DTO와 도메인 모델의 차이와 분리해서 사용해야하는 이유 (0) | 2025.03.13 |