맛동산이

Swift) Task, TaskGroup, .task와 dispatchQueue 본문

앱/Swift

Swift) Task, TaskGroup, .task와 dispatchQueue

진ddang 2023. 7. 4. 13:35

 

Task는 프로그램의 일부를 비동기적으로 실행할 수 있는 하나의 작업 단위이다.

Task는 다음과 같은 특징을 가진다.

  • 순차적 (Sequential)
  • 비동기적 (Asynchronous)
  • 독립적 (Self-contained)

 

Task를 생성할때 클로저를 통해서 해당 Task가 수행할 작업을 정의하게 된다. 즉 async한 작업들을 전부 Task블록을 이용해서 사용해주면 된다.

또한 해당 블록안에 있는 작업이 비동기라는것을 명시적으로 알려준다.

 

Task 사용 예제

func fetchImage() async { 	do { 		guard let url = URL(String: ) else { return } 		let (data, _) = try await URLSession.shared.data(from: url, delegate: nil) 		self.image = UIImage(image: data) 	} catch { 		print(error) 	} } 	 .onAppear { 	Task { 		await fetchImage() 	} }

 

Task의 취소

Task를 사용하면 분명 비동기처리를 할수있다.

하지만 문제는 이렇게 Task를 생성하고, 받아오는 과정에서 화면을 나가거나 해서, Task의 데이터 결과가 필요없는데, 취소를 해주지 않는경우에는 계속해서 메모리를 잡아먹게 되는 문제가 발생한다.

따라서 해당 Task가 필요하지 않을 경우에는 취소를 해주어야 한다.

해당 메소드는 .cancle()을 제공하고 있다.

@State private var fetchTask: Task<(), Failure>? = nil  .onAppear { 	fetchTask = Task { 		await fetchImage() 	} }  .onDisappear { 	fetchTask?.cancle() } 	

checkCancellation()

만약, 여러 조각으로 구성된 긴 작업에서는 여러 지점에서 취소 여부를 확인하고 각 지점마다 다르게 처리해야 할 수 있다. 작업을 중지하기 위해 오류를 throw하는 경우 Task.checkCancellation() 함수를 호출하여 취소 여부를 확인하면 된다.

예를들어

func fetchImage() async {  	for x in array { 		//계속해서 어떠한 작업을 진행하고 있을때 		do { try fetchTask.checkCancellation() } 		catch { print(error) } 	}  	do { 		guard let url = URL(String: ) else { return } 		let (data, _) = try await URLSession.shared.data(from: url, delegate: nil) 		self.image = UIImage(image: data) 	} catch { 		print(error) 	} }

위의 코드에서 해당 Task가 굉장히 오랜시간이 걸리며, 중간에 취소가 되었을때, for x in array루프는 계속해서 돌아갈수 있다.

이런경우 checkCancellation()를 통해서 error를 throw해줄수 있다.

 

.task

swiftUI에서 onAppear과 Task를 합친것이 .task이다.

즉, view appear전에 Task를 먼저 생성하고 실행하게 되는 코드이다.

 

 

Async let과 비동기 처리(병렬적 처리)

하나의 Task안에서 두개의 비동기 처리를 해줄때, await을 사용하게 되면 다음과 같이 된다.

Task { 	let a = await fetchSome() 	let b = await getSome() }

이러한 코드의 문제점은, 두개가 서로 상관관계가 없다면, 동시에 비동기적으로 처리되어도 되는데 하나의 Task에 묶여있어서, a가 응답이 되고 나서 b가 시작되는 문제가 발생한다.

이러한 문제점을 async let을 통해서 처리해준다.

Task { 	async let a = await fetchSome() 	async let b = await getSome() }

이를 통해서 parallel하게 async함수를 작동하며, 프로그래밍을 해줄수 있다.

 

Task와 DispatchQueue 스레드 차이

  • 공통점
    • DispatchQueue 블록 안에 들어가면 임의의 스레드로 처리
    • Task 블록 안에서도 임의의 스레드로 처리
  • 차이점
    • Task 블록 안에서 코드가 대기하여 다음 코드를 실행하지는 않지만, 내부적으로 스레드는 block 되지 않고 다른 일을 처리할 수 있도록 효율적으로 설계

Uploaded by

N2T
반응형