김경록의 앱 개발 여정

[Swift Concurrency] Structured Concurrency 구조적 동시성 본문

TIL

[Swift Concurrency] Structured Concurrency 구조적 동시성

Kim Roks 2025. 4. 15. 19:33

Swift Structured Concurrency

Swift의 Structured Concurrency는 비동기 작업을 계층적으로 구조화하여 코드의 가독성과 안전성을 높이는 방식이다. 이 개념 내에서 async let과 TaskGroup은 병렬 처리를 위한 핵심 도구로 사용된다.

1. async let 활용

개요

async let은 고정된 개수의 비동기 작업을 병렬로 실행할 때 사용된다. 선언된 async let은 즉시 실행되며, 이후에 await 키워드를 사용하여 결과를 기다릴 수 있다. 스코프를 벗어나기 전에 반드시 결과를 await해야 한다.

예시 코드


func fetchUser() async -> String {
    try? await Task.sleep(nanoseconds: 1_000_000_000)
    return "User"
}

func fetchPosts() async -> [String] {
    try? await Task.sleep(nanoseconds: 2_000_000_000)
    return ["Post 1", "Post 2"]
}

func loadData() async {
    async let user = fetchUser()
    async let posts = fetchPosts()

    let (fetchedUser, fetchedPosts) = await (user, posts)

    print("User: \\(fetchedUser), Posts: \\(fetchedPosts)")
}

특징

  • 고정된 수의 비동기 작업에 적합
  • 코드가 간결하며 사용이 직관적
  • await는 반드시 해당 스코프 내에서 수행되어야 함
  • 결과는 순서대로 병합 가능

2. TaskGroup 활용

개요

TaskGroup은 동적으로 생성된 복수의 비동기 작업을 그룹화하여 병렬로 실행할 수 있도록 한다. 작업 수가 가변적인 경우에 적합하며, 각 작업의 완료 시점에 따라 결과를 비동기적으로 수집할 수 있다.

예시 코드

swift
복사편집
func fetchItem(id: Int) async -> String {
    try? await Task.sleep(nanoseconds: UInt64(1_000_000_000 / id))
    return "Item \\(id)"
}

func fetchAllItems() async {
    let ids = [1, 2, 3, 4, 5]
    var results: [String] = []

    await withTaskGroup(of: String.self) { group in
        for id in ids {
            group.addTask {
                await fetchItem(id: id)
            }
        }

        for await result in group {
            results.append(result)
        }
    }

    print("Results: \\(results)")
}

특징

  • 작업 수가 유동적인 경우에 적합
  • 각 작업은 group.addTask를 통해 추가
  • for await를 통해 결과를 순차적으로 수집
  • 에러 전파와 작업 그룹 전체 취소 기능을 지원

3. async let과 TaskGroup 비교

항목 async let TaskGroup

작업 개수 고정 유동적
코드 복잡도 낮음 비교적 높음
사용 용도 간단한 병렬 처리 복잡하고 동적인 병렬 작업
결과 수집 방식 튜플 등으로 동시에 수집 for await로 순차적으로 수집
에러 처리 try 사용 try, throwing TaskGroup 지원
취소 처리 제한적 그룹 전체 취소 가능

 

 

 

공통점

부모 작업이 완료되기 전에 모든 자식 작업이 완료 되도록 기다림(어떤 경우에도 보장됨)

- 자식 작업의 우선 순위가 높아지면 부모 작업의 우선순위 또한 자동으로 높아짐