티스토리 뷰

Swift

[Swift] TaskGroup이란?

ios상우 2024. 4. 11. 15:45

공식문서 설명 번역기 딱 돌리면 동적으로 생성된 자식테스크들의 그룹 이라고 번역되는데

그냥 여러 테스크를 병렬적으로 수행하고싶을때 쓴다고 생각하면 될 것 같음

@frozen
struct TaskGroup<ChildTaskResult> where ChildTaskResult : Sendable

 

실행 방법

withTaskGroup(of:returning:body:) 메소드 사용

  • of: 자식 테스크들의 리턴 타입
  • returning: 그룹 테스트의 리턴 타입이며 하위테스크의 결과로 새로운 타입을 만들어 리턴도 가능함 기본값을 사용하면 하위테스크타입의 배열 형태로 반환
  • body: 작업테스크 추가 구문

 

실행 순서

Tasks added to a task group execute concurrently, and may be scheduled in any order

공식문서에 딱 이렇게 적혀있음 TaskGroups에 추가된 테스크들은 병렬적으로 실행되며 어떤 순서도 될 수 있음. 무작위 즉 순서를 보장할 수 없다는 말임

 

예제

class ContentViewModel: ObservableObject {
    @Published var text = "-"
    
    @MainActor
    @Published var isLoading = false
    
    func getData() {
        Task {
            let result = await withTaskGroup(of: String.self, returning: String.self, body: { @MainActor group in
                isLoading = true
                var result: String = ""
                
                group.addTask {
                    do {
                        let post = try await NetworkService.shared.getPosts(id: 12)
                        return post
                    } catch {
                        print(error)
                        return "-"
                    }
                }
                
                group.addTask {
                    do {
                        let todo = try await NetworkService.shared.getTodos(id: 14)
                        return todo
                    } catch {
                        print(error)
                        return "-"
                    }
                }
                
                while let taskResult = await group.next() {
                    result.append(taskResult)
                    result.append("\\n\\n")
                }
                
                return result
            })
            
            DispatchQueue.main.async {
                self.text = result
                self.isLoading = false
            }
        }
    }
}

 

주의사항

공식문서에 의하면 TaskGroup을 포함하는 스코프 이외에서 TaskGroup에 접근하거나 저장하지 말라고함

예제에서 봤을때 getData() 함수 안에 Task { } 블록 내부에서만 접근하라 이 말임 주의주의

 

작업 취소

  • cancelAll() 메소드를 통해 모든 하위테스크 중지 가능함
  • 이미 cancelAll을 통해 취소된 GroupTask는 AddTask를 통해 또 추가가 가능하지만 바로 취소가 될 것임 그럴 경우addTaskUnlessCancelled(priority:body:) 메소드를 이용하여 취소된 그룹에 테스크가 추가되지 않게 작업이 가능함

 

Async let과는 뭐가 다른가?

  • async let과 task group모두 여러 테스크를 병렬적으로 수행하기 위한 수단임
  • TaskGroup은 위에 TaskGroup을 생성하는 메소드에서 봤다시피 of: 라는 인자레이블에 하위테스크의 리턴타입을 지정하는걸 볼 수 있는데 이를 통해 리턴타입이 모두 일치해야한다는 특징이 있음 추상클래스로 묶거나 enum등의 공통타입으로 묶어 반환하는 방법으로 사용할 수 있지만 다운캐스팅의 번거로움이 존재하니 이런 경우에는 리턴타입이 달라도 상관없는 async let을 사용하는게 좋음
  • async let은 컴파일 시점에 하위 테스크의 개수가 정해져야하며 taskGroup은 그렇지 않음
  • 비교적 간단한 작업은 async let을 이용하나 복잡할수록 더 유연한 taskGroup을 사용함

 

withDiscardingTaskGroup란?

TaskGroup과 같이 동작하지만 하위 테스크들의 결과를 저장해두지 않고 버림

TaskGroup은 모든 하위테스크가 끝나서 TaskGroup이 어떤 값을 반환할때까지 Taskgroup에 저장하고 있으나

DiscardingTaskGroup은 하위 테스크가 끝나는 동시에 결과를 버리기때문에 하위테스크로 인한 어떠한 사이드이펙트가 발생하지 않는 다는 특징이 있음

모든 하위 테스크가 끝나는 즉시 버려지기때문에 함수 종료 직전 테스크그룹은 비어있는걸 볼 수 있음

→ 하위 테스크의 결과가 필요 없는 경우 이걸 사용하는게 사이드 이펙트가 없으므로 좋음

 

withThrowingTaskGroup란?

제목에서 유추 가능할 것이라고 생각함! taskgroup내부에서 던질 수 있게해주는 taskgroup 동작은 같음

«   2025/03   »
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 31
공지사항
링크
Total
Today
Yesterday