적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

초보 iOS 개발자의 일상/개발 업무

비동기 Task 병렬 실행 (TaskGroup vs. async let)

hongssup_ 2024. 12. 9. 12:07
반응형

커뮤니티 사연 불러오기 전에 contents 를 먼저 받아와야 한다. 

Task {
    await fetchBanners()          // 첫 번째 API 호출 (비동기적으로 실행, 완료될 때까지 대기)
    await fetchEmpathyStories()   // 두 번째 API 호출 (첫 번째가 끝난 후 실행)
    await fetchMacasPickStories() // 세 번째 API 호출 (두 번째가 끝난 후 실행)
    await fetchHashtags()         // 네 번째 API 호출 (세 번째가 끝난 후 실행)
    
    process(.fetchStories)        // 모든 작업이 완료된 후 실행
}

이렇게 하면 비동기로 네 개 동시에 실행하고 마지막에 사연 리스트 호출하는 줄 알았는데, 그냥 순차 실행이었음

Task 는 비동기 컨텍스트를 생성

await 키워드는 비동기 작업이 완료될 때까지 기다림

순차 실행..

 

병렬 실행이 필요하다면 async let 또는 TaskGroup 을 사용하는 것이 적합하다.

 

1. async let 을 사용한 병렬 실행

Task {
    async let banners = fetchBanners()
    async let empathyStories = fetchEmpathyStories()
    async let macasPickStories = fetchMacasPickStories()
    async let hashtags = fetchHashtags()

    await banners
    await empathyStories
    await macasPickStories
    await hashtags
    
    process(.fetchStories)
}

 

2. TaskGroup을 사용한 병렬 실행

Task {
    await withTaskGroup(of: Void.self) { group in
        group.addTask { await fetchBanners() }
        group.addTask { await fetchEmpathyStories() }
        group.addTask { await fetchMacasPickStories() }
        group.addTask { await fetchHashtags() }
    }
    
    process(.fetchStories)
}

 

 

 

+

api 호출 후에 스크롤을 제어해야하는데, 호출 후 시점이 안맞는지 바로는 안되고 0.3초 정도 후에는 잘 되더라.

GCD 기반으로는 DispatchQueue.main.asyncAfter를 사용하겠지만

SwiftConcurrency 환경에서는 Task.sleep을 쓰면 await 와 함께 연계하여 간편하게 사용할 수 있다.

 

Task {
    async let story: () = fetchSingleStory(storyID: id)
    async let comments: () = fetchComments(storyId: id, commentType: .story)

    await story
    await comments

    try? await Task.sleep(nanoseconds: 3_000_000_000)
    
    state.scrollPosition = .expertComment
}

저 나노세컨드가 거슬리면 다음과 같이 TimeInterval 을 확장해서 nanosecond로 변환해 사용할 수 있다. 

// try? await Task.sleep(nanoseconds: 0.3.toNanoseconds)

extension TimeInterval {
    var toNanoseconds: UInt64 {
        return UInt64(self * 1_000_000_000)
    }
}

 

 

차이점 비교

Task.sleep DispatchQueue.main.asyncAfter
Swift Concurrency GCD 기반
가벼운 suspend 호출, 추가적인 컨텍스트 전환 없음 더 무겁고, 추가적인 컨텍스트 전환 필요
Task.cancel() 로 취소 가능 취소 불가능
728x90
반응형