작업 기반 비동기 패턴 TAP(Task-based Asynchronous Pattern)
Task 클래스를 사용해 비동기 작업을 통제하는 패턴으로 async-await, Task를 사용해 바동기 프로그래밍을 단순화 합니다.
Task 클래스
비동기 작업의 결과를 나타냅니다, 작업이 완료되기를 기다리거나 작업의 결과를 받아올 수 있습니다.
Task.Run이나 Task.Factory.StartNew와 같은 메서드를 사용한다면 TaskScheduler를 통해 관리되고
만약 async-await에서 await가 대기하는 Task는 SynchroniztionContext에 의해 관리됩니다.
TaskScheduler
.NET의 TaskScheduler 클래스를 통해 Task의 실행을 관리합니다.
Task가 실행될 스레드를 결정하고 Task들의 우선순위를 조정합니다.
ThreadPool을 사용하여 멀티 스레딩이 가능합니다.
ThreadPool
스레드를 효율적으로 관리하며, 스레드의 생성 및 소멸에 따른 오버헤드를 줄여줍니다.
개발자가 ThreadPool 관리에 대해 걱정할 필요 없이 비동기 작업을 쉽게 구현할 수 있습니다.
정리
개발자는 Task API를 사용하여 비동기 작업을 쉽게 관리하고 추적할 수 있습니다.
내부적으로 TaskScheduler와 ThreadPool를 통해서 작업을 처리합니다.
async 키워드
C#에서 비동기 메서드를 선언할 떄 사용됩니다.
메서드 내부에서 await 키워드를 사용해 비동기 작업을 간결하게 표현할 수 있습니다.
async 메서드 자체는 호출된 시점의 동기화 컨텍스트
에서 작업을 바로 시작하게됩니다.
만약 await 키워드가 없다면 동기 방식으로 작동하게 됩니다.
await 키워드
async 메서드 내부에서 사용됩니다. 실제 비동기 작업을 시작해 Task를 반환받고 완료를 기다립니다.
해당 Task가 완료될 때까지 현재 async 메서드를 일시 중단하고 TaskScheduler에 의해 대기 상태로 관리됩니다.
이때 호출 스레드는 대기하지 않고 계속해서 다음 작업을 처리합니다.
Task가 완료되면 현재 async 메서드가 TaskScheduler에 의해 활성 상태가 되고 중단된 지점부터 실행을 재개합니다.
async void
async void 는 Task를 반환하지 않기 때문에 TaskSchedular로 추적, 관리할 수 없습니다.
추적, 관리할 수 없고 예외 처리가 어렵기 때문에 void 반환이 요구되는 이벤트 핸들러에서 주로 사용되고 일반적으로는 사용을 지양합니다.
비동기 작업의 완료후 돌아가게될 스레드를 결정합니다.
유니티의 동기화 컨텍스트
유니티 API는 메인 스레드가 아닌 스레드에서 호출할 경우 문제가 생길 수 있어 주의해야 합니다.
하지만 유니티 동기화 컨텍스트에 의해 async 호출과 await 이후의 작업을 메인스레드에서 하도록 관리됩니다.
그래서 async 내부에서 리소스 로드 후 유니티 API를 사용하여 작업을 진행할 수 있습니다.
코루틴과의 차이점은? 유니티 상에서 사용할떄 주의할점?
- 코루틴은 Unity, TAP는 C#에서 지원하는 기능이다.
- 코루틴은 단일 스레드, TAP는 멀티 스레드를 사용할 수 있다.
- 코루틴은 작업을 실행, 대기 시키며 하나의 스레드에서 여러 작업을 유연하게 실행
- Unity에서 Task를 사용할 때는 유니티 API의 스레드 안전성을 고려해야 한다.
- async-await 패턴은 유니티의 동기화 컨텍스트로 관리되어 일반적으로는 안전하다.