- TaskGroup2023년 08월 13일
- 2료일
- 작성자
- 2023.08.13.:01
TaskGroup
뭐 간단한 병렬실행이면 async let을 써주면 된다. 하지만 이게 수없이 많다면? async let 계속쓸래??
또한 static하게 결정된 task에서만 쓸수 있다. 왜? 우리가 async let 으로 다 일일이 해줘야하기에!!
만약 모든 이미지를 가져와야하는경우 필요한 개수를 미리 알수 있을까?
⇒ nono 그건 컴파일시점에 알수 있는것이 아닌 런타임 시점에 알수 있다.
TaskGroup
- 런타임때마다 달라질수 있는 child Task들을 동적으로 만들어줄수 있다!! 😆 😆 😆
Taskgroup을 만들기 위해서는 withTaskGroup(of:returning:body:)를 호출!
throwing taskgroup → withThrowingTaskGroup(of:returning:body:) 에러던질때! 에러가 없을때만 결과값 리턴.
of: childTask의 결과 타입
**func** withThrowingTaskGroup<ChildTaskResult, GroupResult>(of childTaskResultType: ChildTaskResult.Type, returning returnType: GroupResult.Type = GroupResult.self, body: (**inout** ThrowingTaskGroup<ChildTaskResult, Error>) **async** **throws** -> GroupResult) **async** **rethrows** -> GroupResult **where** ChildTaskResult : Sendable
보면 async로 이루어져있기에 함수 호출할때 await붙여야함.
func fetchImageWithAsyncLet() async throws -> [UIImage] { async let fetchImage1 = fetchImage(urlString: "<http://picsum.photos/300>") async let fetchImage2 = fetchImage(urlString: "<http://picsum.photos/300>") async let fetchImage3 = fetchImage(urlString: "<http://picsum.photos/300>") let (image1,image2,image3) = await (try fetchImage1, try fetchImage2, try fetchImage3) return [image1,image2, image3] } func fetchImagesWithTaskGroup() async throws -> [UIImage] { return try await withThrowingTaskGroup(of: UIImage.self){ group in var images: [UIImage] = [] group.addTask { try await self.fetchImage(urlString: "<http://picsum.photos/300>") } group.addTask { try await self.fetchImage(urlString: "<http://picsum.photos/300>") } group.addTask { try await self.fetchImage(urlString: "<http://picsum.photos/300>") } group.addTask { try await self.fetchImage(urlString: "<http://picsum.photos/300>") } for try await image in group { images.append(image) //만약 여기서 위4개중하나라도 안오면 계속 기다리게 된다. } return images } }
async let → taskgroup으로~
마찬가지로 4가지 일이 병렬처리 되어진다.
try await image in group에서 만약 위 4개의 child task의 일이 끝나지 않는다면 여기서 await를 해줌!
addTask
**mutating** **func** addTask(priority: TaskPriority? = nil, operation: **@escaping** () **async** **throws** -> ChildTaskResult)
group안에 child Task를 만들어준다. 그룹에 넣어주면 즉각적으로 어떤 순서로든 실행된다.
priority를 통해 우선순위를 정해줄수 있고 operation에 원하는 작업을 넣어주면 된다.
group.addTask(operation: () async throws -> UIImage)
자동완성이 이렇게 되는 이유는 operation의 리턴타입은 우리가 만들어준 Taskgroup의 of파라미터를 따라간다.
그런데 이전과 같이 addTask를 각각 써주면 여전히 코드가 길고 이쁘지 않고 async let과 비교했을때 뭐가 장점인지 잘 모르겟다.. 사실 저렇게 잘 안씀! 저건 예제일뿐!
func fetchImagesWithTaskGroup() async throws -> [UIImage] { let urlStrings = [ "<http://picsum.photos/300>", "<http://picsum.photos/300>", "<http://picsum.photos/300>", "<http://picsum.photos/300>", "<http://picsum.photos/300>", ] return try await withThrowingTaskGroup(of: UIImage.self){ group in var images: [UIImage] = [] images.reserveCapacity(urlStrings.count) for urlString in urlStrings { group.addTask { try? await self.fetchImage(urlString: urlString) } } for try await image in group { images.append(image) } return images } }
위와같이 for문을 통해 addTask를 해준다!!
새로생긴 배열.reserveCapactiy는 무엇일까?
swift는 모든 배열을 데이터 저장할수있는 특정양의 메모리를 예약한다. capacity!!
이 capacity를 초과하면 다시 배열은 더큰 메모리 영역을 할당해준다.
잠깐 딴길로 샛지만 궁금해서 한번해봄
import UIKit var arr: [Int] = [] var currentCapacity = arr.capacity (0..<5000).forEach { element in arr.append(element) if (arr.capacity != currentCapacity) { print(arr.capacity) currentCapacity = arr.capacity } }
초반에 2의 제곱수로 늘어나다 어느순간부터 이상함 ㅋ
일반적으로 재할당은 성능에 문제가 없다.
But) 배열이 매우매우큰 것을 알고 있는경우나 성능에 민감한 배열인경우에 재할당을 방지하기 위해 사용하는 함수가 reserveCapacity! 최소 capacity를 정해준다. 이거 넘으면 터지냐? ㄴㄴ 새로 다시 재할당받아
기존의 코드에서는 한번이라도 에러가 발생하면 전체에서 에러를 throw한다. 즉 urlString이 뭐 하나 잘못 입력하면? 아예 error라 뷰가 안띄어져 ㅠㅠ
이걸 막으려면 에러가 발생하는 것은 nil를 반환하도록 옵셔널로 해준다. 이러면 뭐 잘못받은것만 안나오고 제대로 받은것들은 나오게 된다.
next()
다음 child task가 끝날때까지 기다렸다가 반환된 값을 return!
mutating func next() async -> ChildTaskResult?
- 작업이 완료된 순서로 나타낸다.
- 빈 그룹은 중지하지 않고 즉시 nil을 리턴한다.
for try await image in group { images.append(image) } while let image = try await group.next() { images.append(image) }
위에서 사용한 for문을 next를 사용하여 바꿔줄수도 있다.
'면접준비' 카테고리의 다른 글
KeyChain (1) 2023.10.08 Combine(2)- Operator (1) 2023.10.08 Swift Concurrency - Async, Await (0) 2023.08.08 Combine3-Cancellable (0) 2023.07.09 Combine(1)-WhatisCombine(publish&subscirbe) (0) 2023.07.09 다음글이전글이전 글이 없습니다.댓글