Swift 5.7 매뉴얼에서 Concurrency 챕터에서는 Task and Task Group
이라는 개념이 소개되고 있는데 오키 내용은 알겠고 어떻게 쓰라고? 하다가 이거 나중에 프로젝트에서 써먹어야지 하는 생각으로 기록하는 예시 코드이다.
https://developer.apple.com/documentation/swift/taskgroup
자세한 내용은 공식문서를 참고!
class TaskGroupTest {
func test() async {
// starts a new scope that can contain a dynamic number of child task
await withTaskGroup(of: Data.self) { taskGroup in
let photoNames = await listPhotos(inGallery: "Summer Vacation")
for name in photoNames {
taskGroup.addTask {
await self.downloadPhotos(name: name).data(using: .utf8)!
}
}
}
}
withTaskGroup
함수! of:
에는 각 child task가 반환하는 결과값의 Type을 넘긴다.addTask
하면 그 child task들이 착착 실행된다. (inout TaskGroup<ChildTaskResult>) async -> GroupResult)
https://developer.apple.com/documentation/swift/withtaskgroup(of:returning:body:)
자세한 내용은 역시나 공식문서 참고가 최고!
addTask
를 좀더 자세히 살펴보자.mutating func addTask(
priority: TaskPriority? = nil,
operation: @escaping () async -> ChildTaskResult
)
childTaskResult로 반환되는 값의 type이 당연히 of: 의 type 과 동일해야
한다는 것이다!나의 경우에는, 공식문서를 봐도 그래서 저 withTaskGroup의 결과물을 어떻게 써먹어야 할지 감이 오지 않았다. 공식 문서는 나를 너무 고평가한 것이다! 그래서 나는 내가 이해할만한 쉬운 예시를 만들어 보았다.
func printMessage() async {
let words = ["Hello", "My", "name", "is", "yujinj"]
let string = await withTaskGroup(of: String.self) { taskGroup -> String in
for word in words {
taskGroup.addTask {
// 시간이 소요되는 작업을 진행
// let data = await requestToServer(word)
// 서버와 통신 후 결과 데이터 반환 (여기서는 그냥 word로 퉁친다.)
return word + " (by Server) "
}
}
var collection = [String]()
// taskGroup을 결과값이 들어있는 리스트라고 생각한다.
for await value in taskGroup {
collection.append(value)
}
return collection.joined(separator: " ")
}
print("said:", string)
}
add
하였다.let string
에 담길 것이다."said: Hello (by Server) My (by Server) name (by Server) is (by Server) yujinj (by Server)"
func sumNumbers() async {
let numbers = [1, 2, 3, 4, 5]
let total = await withTaskGroup(of: Int.self) { taskGroup -> Int in
for num in numbers {
taskGroup.addTask{
// 복잡하고 시간이 걸리는 로직이 진행된다...
return num
}
}
let reduceResult = await taskGroup.reduce(0,+)
return reduceResult
}
await MainActor.run {
// UI update
}
print("total", total)
}
MainActor
를 사용할 수 있다. async-await와 함께 사용하면 더 시너지를 발휘할 taskGroup! 다음에 회사에서 이렇게 써봐야지 하는 생각을 하고 있다. DispatchGroup과 비슷하게 사용할 수 있을 것 같고 task의 cancellation에 대해서는 다음에 다시 살펴보겠다.