SC #11: 작업 그룹
I’m happy to translate the article for you, but I don’t have the full text of the post. Could you please paste the content you’d like translated (excluding the source line you already provided)? I’ll keep the source link at the top, preserve all formatting, code blocks, URLs, and technical terms, and translate the rest into Korean.
TaskGroup
TaskGroup는 동적으로 생성된 하위 작업들을 포함하며, 순차적으로 또는 동시에 실행될 수 있습니다. 그룹은 모든 하위 작업이 완료될 때만 종료된 것으로 간주됩니다.
withTaskGroup(of:returning:isolation:body:)는 addTask(priority:operation:)를 사용하여 하위 작업을 추가할 수 있는 컨텍스트를 생성합니다.
기본 예제: 이미지 다운로드
func downloadPhoto(url: URL) async -> UIImage {
// …
}
await withTaskGroup(of: UIImage.self) { taskGroup in
let photoURLs = await listPhotoURLs(inGallery: "Vacaciones")
for photoURL in photoURLs {
taskGroup.addTask {
await downloadPhoto(url: photoURL)
}
}
}
TaskGroup은 각 하위 작업을 동시에 실행하는 forEach와 같이 동작하며, 결과를 저장합니다.
결과 수집
컬렉션으로
반환 타입을 컬렉션으로 정의할 수 있습니다(예: [UIImage].self). 모든 서브태스크를 시작한 뒤, 그룹의 AsyncSequence를 사용해 결과를 기다리고 최종 컬렉션을 구성합니다.
let images: [UIImage] = await withTaskGroup(
of: UIImage.self,
returning: [UIImage].self
) { taskGroup in
let photoURLs = await listPhotoURLs(inGallery: "Vacaciones")
for photoURL in photoURLs {
taskGroup.addTask {
await downloadPhoto(url: photoURL)
}
}
var images = [UIImage]()
for await result in taskGroup {
images.append(result)
}
return images
}
reduce 사용
TaskGroup이 AsyncSequence를 구현하므로 reduce 연산자를 사용할 수도 있습니다.
await withTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
let photoURLs = try! await listPhotoURLs(inGallery: "Vacaciones")
for photoURL in photoURLs {
taskGroup.addTask {
try! await downloadPhoto(url: photoURL)
}
}
return await taskGroup.reduce(into: [UIImage]()) { partialResult, image in
partialResult.append(image)
}
}
ThrowingTaskGroup
어떤 하위 작업이 오류를 발생시킬 수 있을 때는 withThrowingTaskGroup(of:returning:isolation:body:)를 사용합니다.
try await withThrowingTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
let photoURLs = try await listPhotoURLs(inGallery: "Vacaciones")
for photoURL in photoURLs {
taskGroup.addTask {
try await downloadPhoto(url: photoURL)
}
}
return try await taskGroup.reduce(into: [UIImage]()) { partialResult, image in
partialResult.append(image)
}
}
오류 발생 시 동작
ThrowingTaskGroup은 하위 작업이 예외를 발생시켜도 자동으로 실패하지 않습니다; 해당 하위 작업은 실패로 표시되지만 그룹은 계속 실행됩니다.- 오류를 전파하고 남은 작업을 취소하려면
group.next()를 사용해 각 하위 작업을 명시적으로 언패킹해야 합니다.
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask { throw SomeError() }
// 여기서는 그룹이 실패하지 않음
}
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask { throw SomeError() }
try await group.next() // 오류를 전파하고 진행 중인 작업을 취소함
}
next()
group.next() 은(는) 서브태스크의 결과를 하나씩 무작위 순서로 제공하고, 서브태스크가 실패하면 해당 오류를 발생시킵니다. 이를 통해 각 오류를 개별적으로 처리할 수 있습니다.
while let result = try await taskGroup.next() {
print("Got a new result:", result)
}
작업 취소
group.cancelAll()을 사용하여 전체 작업 집합을 취소할 수 있습니다.addTask(priority:operation:)으로 이미 취소된 그룹에 작업을 추가하면, 작업은 생성된 직후 즉시 취소됩니다. 작업이 시작조차 하지 않도록 하려면addTaskUnlessCancelled(priority:operation:)를 사용하십시오.
for photoURL in photoURLs {
let didAddTask = taskGroup.addTaskUnlessCancelled {
try await downloadPhoto(url: photoURL)
}
print("Added task: \(didAddTask)")
}