Hamp 2024. 10. 23. 23:01
반응형

Task

정의

A unit of asynchronous work.

 

@frozen
struct Task<Success, Failure> where Success : Sendable, Failure : Error

 

  • 구조체로 만들어진 비동기 작업 단위
  • 독립적인 스레드에 할당되도록한다.
  • 작업은 병렬적으로 일처리를 진행

구조

1. 리턴 값

let task: Task<String, Never> = Task {
    return "String"
}
  • 작업 성공 시 결과 값
  • Success와 Failure를 지정해줄 수 있다. 여기서 리턴 값은 Success에 해당되는 부분이다.
  • 변수.value 를 이용해서 얻어 낼 수 있다.
  • 위 코드에서는 String에 해당된다.

2. 결과 값

  • 리턴 값과 혼동이 될 수 있지만 말그대로, Result<Success,Failure> 형태로 받는다.
  • 변수.result로 얻을 수 있다.
  • Task 블럭 내에서 발생하는 Error를 Task가 result 변수를 통해 Error를 받을 수 있다.

3.  우선 순위

  • Task 생서 시 우선순위를 줄 수 있다.
public static let userInitiated: TaskPriority // 25
public static let high: TaskPriority // 25
public static var medium: TaskPriority { get } // 21
public static let low: TaskPriority // 17 
public static let utility: TaskPriority // default // 17
public static let background: TaskPriority // 9

 


특징

1. Task는 상위  컨텍스트를 상속받는다.

let task = Task(priority: .medium) {
   
    print("부모 Task 1 실행")
    print("부모 Task 1 우선순위: \(Task.currentPriority)")
    print("부모 Task 1 취소 여부 \(Task.isCancelled)")
    
    Task {
        print("부모 Task 2 실행")
        print("내부 Task 2 우선순위 \(Task.currentPriority)")
        print("내부 Task 2 취소 여부 \(Task.isCancelled)")
    }
}
  • 우선순위 , Actor isoldated (실행 주체),  Task local 3가지를 상속 받는다.
  • 취소는 상속 받지 않는다. 즉, 바깥이 취소되었다고 무조건 내부 Task가 취소되지는 않는다.
  • 변수에 Task를 담지 않으면 즉시 실행되고 작업을 변수에 담으면 도중에 cancle이 가능하다

 

2. Task 내부는 순차적으로 동작한다.

  • 직렬큐와 유사하다.



3. Task 내부에서는 self를 붙히지 않아도 된다.

 

이유는 여러개 있다.

 

1. @_implicitSelfCapture

  • 스터디에서 들은 내용으로는 Task 생성자에  @_implicitSelfCapture가 있어 암시적으로 캡쳐를 진행 함 (코드 링크는 추후 첨부) 

2. self객체가 Task보다 오래살아있음

  • self 객체의 생명주기가 대부분 Task보다 길기 때문에
  • 반대로 말하면, Task body의 작업이 무거워 self 객체의 생명주기보다 길때, weak self를 써야한다는 의미 (대표적으로 비동기 반복문)
  • 이 내용도 Task Cancel 전파를 이용해 충분히 대체가 가능함

3.Sending

  • 우리는 탈출 메서드에 self를 반드시 명시해야한다고 했지만 앞에 sending 키워드를 붙히면 다음과 같은 효과가 있다.
  • sending 함수 매개변수나 결과값이 안전하게 isolation 경계를 넘어 전송될 있음을 나타낸다.
  • 즉 명시적으로 self를 캡처하지 않아도 , 암시적으로 self를 캡처한다.
  • 작업이 끝나면, self를 자동으로 해체가 되어 강한 참조가 될 수 없다. 
  • 자세한 것은 공식문서 Task closure lifetime 을 살펴보자.

 

@isolated(any)


Task.yield()

Suspends the current task and allows other tasks to execute.

 

CPU에게 오래 걸리는 작업이 있으니 thread를 양보하는 역할

  • 타입 메서드 
  • DB 작업과 같이 도중에 중단되는 작업은 호출하면 안된다.
func tempAsyncFunc() async -> String {
	
    let a = await func1()
    
    await Task.yield() // 밑에 오래걸리는 작업 전에 , 스레드 양보 
    
    let b = await func1()
	
}

Task.detached

Runs the given nonthrowing operation asynchronously as part of a new top-level task.

 

  • 특징 1, 3번을 무시하는 Task , 즉 context를 물려받지 않기 때문에 self가 캡쳐되지 않아 꼭 self를 사용해야함
  • 기존은 context를 물려받지 않은 분리된 작업 생성
  • 최대한 지양해서 사용 ..

참고

 

Task | Apple Developer Documentation

A unit of asynchronous work.

developer.apple.com

 

 

yield() | Apple Developer Documentation

Suspends the current task and allows other tasks to execute.

developer.apple.com

 

반응형