← Study Hub

10 · TaskGroup

스코프를 못 벗어나는 이유, 그리고 결과가 도착하는 순서
진행률
0 / 0 완료

← 문항 인덱스

면접 질문
  1. 그룹 스코프를 벗어나기 전에 자식 태스크가 안 끝났다면?
  2. 자식 태스크의 결과 순서는 추가한 순서와 같나요?

답변 ① — 벗어날 수 없다 (다만 기다림 ≠ 취소) 🔥 핵심

결론부터 말하면 벗어날 수 없습니다. withTaskGroup은 클로저가 return하기 전에 모든 자식이 완료될 때까지 암시적으로 await합니다. next()를 한 번도 호출하지 않아도 마찬가지입니다. 이것이 구조적 동시성의 보장이며, 그룹을 벗어난 뒤 자식이 떠도는 상황은 생기지 않습니다.

여기서 반드시 구분해야 할 것이 "기다린다(await)"와 "취소한다(cancel)"입니다.

⚠️ 주의

"조기 return하면 남은 작업이 취소되겠지"라고 착각하기 쉽습니다. 정상 return은 취소 없이 끝까지 기다립니다. 불필요한 네트워크 호출이 계속 도는 원인이 되니, 정말 멈추고 싶으면 cancelAll()을 명시적으로 부르세요.

📝 노트

또 하나: 자식의 에러는 자동으로 그룹을 실패시키지 않습니다. for try awaitnext()순회해야 에러가 전파됩니다. 결과를 안 쓴다고 순회를 생략하면 에러가 조용히 사라집니다.

암시적 await ≠ 암시적 cancel (Swift)
await withTaskGroup(of: Void.self) { group in
    group.addTask { await longWork() }

    // next()를 한 번도 안 불러도,
    // 클로저가 끝나기 전에 longWork() 완료까지 반드시 기다린다.

    group.cancelAll()   // 조기에 '취소'하려면 이렇게 직접 불러야 한다
                        // (그래도 자식이 취소에 반응해 끝나야 반환된다)
}

답변 ② — 아니다. 완료 순서로 도착한다

결과 순서는 추가한 순서와 다릅니다. 그룹은 AsyncSequence처럼 동작해 먼저 끝난 자식부터(완료 순서) 결과를 내보냅니다. 빠른 작업이 먼저, 느린 작업이 나중에 옵니다. 따라서 addTask 순서에 의존하는 코드는 실행할 때마다 결과가 달라지는 버그가 됩니다.

순서가 필요하면 방법은 둘입니다.

이건 단점이 아니라 설계 의도입니다. 완료 순서로 흘려보내야 먼저 끝난 결과를 즉시 처리할 수 있어(스트리밍) 전체 지연이 줄어듭니다. 순서는 필요한 쪽에서만 복원하면 됩니다.

결과는 완료 순서로 온다 — 인덱스로 원래 순서를 복원 (Swift)
func fetchAll(_ urls: [URL]) async -> [Data] {
    await withTaskGroup(of: (Int, Data).self) { group in
        for (i, url) in urls.enumerated() {
            group.addTask { (i, await fetch(url)) }    // 번호표(i)를 같이 들려 보낸다
        }

        var byIndex: [Int: Data] = [:]
        for await (i, data) in group {                 // 먼저 끝난 것부터 도착한다
            byIndex[i] = data
        }
        return urls.indices.map { byIndex[$0]! }       // 원래 순서로 재정렬
    }
}

쉽게 이해하기

TaskGroup은 심부름 여러 개를 동시에 내보내고, 부모는 문 앞에서 다 돌아올 때까지 기다리는 거예요.

(질문 ①) 아직 안 온 아이가 있으면 그냥 나갈 수 없습니다. 여기서 헷갈리기 쉬운 게 있어요. 중간에 "난 이제 됐어" 하고 나가려 해도, 남은 아이들을 다 기다려 줍니다. 왜냐하면 기다리는 것"그만 와!"라고 부르는 것은 다른 일이거든요. 결과가 더 이상 필요 없어도 아이들은 심부름을 끝까지 하고 옵니다. 진짜로 그만 시키고 싶으면 직접 외쳐야 해요.

(질문 ②) 아이들이 돌아오는 순서는 '보낸 순서'가 아니라 '빨리 끝난 순서'예요. 가까운 데 간 아이가 먼저 오죠. 이건 일부러 그렇게 만든 거예요 — 먼저 온 결과를 바로 쓸 수 있으니까요. 그래서 순서를 맞추고 싶으면 아이마다 번호표를 들려 보내고, 다 온 다음에 번호대로 줄을 세우면 됩니다.

🔑 한 문장

그룹은 반드시 다 기다리지만, 저절로 취소해 주지는 않는다. 도착 순서는 보낸 순서가 아니다.