Загружаем каталог…
Загружаем каталог…
지난 글 에서는 Coroutine 에 대해 다뤘었다. 관련해 설명하면서, 이제는 코루틴은 사용하지 않고 UniTask 로 많이들 넘어가서, UniTask 위주로 사용한다고 설명했다. Coroutine이 밀려나는 이유 간략하게 왜 Coroutine 을 사용하지 않게 된 건지 다시 알아보자. 반환형 사용 불가능 반환형이 사용 불가능하다. Coroutine 은 반드시 IEnuemrator 형을 반환형으로 가져야 하기 때문에, 내부 로직에 의해 산출된 결과물을 받아서 사용할 방법이 없다. 예외 처리 불가능 우리가 Coroutine 을 통해 비동기적으로 처리하고자 하는 작업들은 네트워크 통신, 파일 읽기처럼 오래 걸리는 작업도 포함되는데 예외처리가 불가능하면...문제가 많다. GC 부담 발생 흔히 사용하는 yield return new WaitForSeconds(); 같은 함수를 사용하면 new 이기 때문에 동적할당 발생하면서 GC가 감당해야 할 객체가 늘어난다. 생명주기 종속 생명주기가 Monobehaviour 에 종속되어있는 것도 문제이다. 그래서 MonoBehaviour 가 죽으면 사라지면서 뒤처리를 못하고 상태를 꼬아둔 상태로 사라지는 일도 잦음. UniTask 특징 Unity에 최적화 된 비동기 프로그래밍 라이브러리로, 다음과 같은 특징이 있다. 구조체 기반 -> GC할당 없음 Unity PlayerLoop와 통합 되어 메인 스레드에서 동작 -> Unity 에서의 사용감 좋음 async/await 완벽 지원 -> 직관적, 안정적인 비동기 코드 사용 방법 UniTask 를 어떻게 사용하는지, 문법에 대해 알아보자. 반환 타입 UniTask 가장 기본적인 방식으로, 반환값이 없는 경우에 사용한다. async UniTask DoTask() { await UniTask.Delay(1000); Debug.Log("작업 완료"); } UniTask<T> 비동기 작업의 결과를 반환해야 할 때 사용한다. T 는 제네릭으로, 반환값의 자료형을 명시한다. async UniTask<int> GetScore() { await UniTask.Delay(1000); return 100; } // 호출 int score = await GetScore(); Debug.Log(score); // 100 UniTask<T> 결과를 기다릴 필요 없는, Fire And Forget 전용이라고 보면 된다. 호출 시에 await 의 사용 자체가 불가능함. async UniTaskVoid LogMessageAsync() { await UniTask.Delay(1000); Debug.Log("Fire and Forget"); } // 호출 (await 없음) LogMessageAsync().Forget(); 위의 세 가지 설명에 대해서 그림으로 간단히 요약하면 아래와 같다. 핵심 API 이제 코루틴 내부에서 사용하는 핵심 API에 대해서 알아보자. UniTask.Delay() 특정 시간(ms)만큼 대기한다 async UniTaskVoid MyTask() { await UniTask.Delay(1000); Debug.Log("완료!"); } UniTask.DelayFrame() 특정 프레임 만큼 대기한다. async UniTaskVoid MyTask() { await UniTask.DelayFrame(10); Debug.Log("열 프레임 지남"); } UniTask.Yield() 현재 실행을 중단하고 Unity PlayerLoop에 제어권을 반환한 뒤, 지정된 PlayerLoopTiming에서 실행을 이어간다. 하나의 큰 작업을 나누어 처리할 때 주로 사용함. // 다음 Update까지 대기 await UniTask.Yield(); // 다음 FixedUpdate까지 대기 await UniTask.Yield(PlayerLoopTiming.FixedUpdate); // LateUpdate 이후(PostLateUpdate)까지 대기 await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); UniTask.WhenAll() 병렬로 여러 개의 UniTask작업을 수행하며, 모두 완료될때까지 대기한다. 독립적인 비동기 작업을 순차 실행하는 것보다 빠를 확률이 높다. 물론 그렇다고 멀티스레딩 기반으로 동작하는 것은 아니기에, 내부에 대기 작업이 없다면 빠르지 않기도 하다. // 여러 작업 병렬 실행 async UniTask<string> LoadData1() { /* ... */ } async UniTask<string> LoadData2() { /* ... */ } async UniTask<string> LoadData3() { /* ... */ } // WhenAll로 병렬 실행 var (result1, result2, result3) = await UniTask.WhenAll( LoadData1(), LoadData2(), LoadData3() ); Debug.Log($"{result1}, {result2}, {result3}"); UniTask.WhenAny() 역시 병렬적으로 실행하나, 하나만 완료되면 종료된다. async UniTask<string> Server1() { /* ... */ } async UniTask<string> Server2() { /* ... */ } // 먼저 완료된 작업 사용 // 개별 인자 오버로드는 (winArgumentIndex, result1, result2) 3-튜플을 반환 var (winIndex, result1, result2) = await UniTask.WhenAny( Server1(), Server2() ); var result = winIndex == 0 ? result1 : result2; if (winIndex == 0) Debug.Log("Server1이 먼저 응답"); else Debug.Log("Server2가 먼저 응답"); 이를 통해 TimeOut등을 관리할 수도 있다. 타임아웃용 타이머와 특정 작업을 수행시키고 타이머가 먼저 끝나면 타임아웃으로 처리하는 등의 방법 CancellationToken UniTask는 실행 중간에 취소할 수도 있다. 아래와 같이 사용 가능 // 외부에서 TokenSource 생성 private void StartLevel() { CancellationTokenSource cts = new CancellationTokenSource(); // 토큰 넣어서 호출 MyUniTask(levelCts.Token).Forget(); } // 실행되면, 토큰 무효화됨 private void OnDestroy() { cts.Cancel(); cts.Dispose(); } // 토큰 받아서 실행 async UniTask MyUniTask(CancellationToken ct) { DoTask(); // 2초 대기 도중 cts가 무효화되면 종료됨 await UniTask.Delay(2000, cancellationToken: ct); } CancelltationTokenSource에서 뽑힌 Token은 Source가 Cancel 되면 효력이 사라진다. Cancel 시에는 하는 김에 Dispose 까지 해주면 좋음. CancellationToken 덕분에 UniTask는 생명주기를 보다 편리하게 관리할 수 있게 된다. 정리 Coroutine 도 여전히 간단한 연출이나 시간 제어에는 충분히 사용할 수 있다. 하지만 작업의 결과를 반환해야 하거나, 여러 비동기 작업을 함께 관리하고, 예외 처리와 취소까지 고려해야 한다면 코드가 점점 복잡해진다. UniTask 는 async/await 를 기반으로 이러한 작업들을 비교적 자연스럽게 표현할 수 있고, Unity의 PlayerLoop 와 통합되어 있어 Unity 환경에서도 부담 없이 사용할 수 있다. 특히 CancellationToken 을 이용하면 오브젝트가 사라지거나 더 이상 작업이 필요하지 않은 상황에서 실행 중인 비동기 작업까지 함께 정리할 수 있다. 결국 단순히 Coroutine 의 문법을 UniTask 로 바꾸는 것이 아니라, 비동기 작업의 시작부터 결과 반환, 대기, 예외 처리, 취소까지 하나의 흐름으로 관리할 수 있다는 점 이 UniTask 를 사용하는 가장 큰 이유일 것이다. 우리도 UniTask 를 사용해 보다 효율적으로 비동기 흐름을 구현해보자.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
왕위를 계승하는 중입니다 - UniTask. 지난 글 에서는 Coroutine 에 대해 다뤘었다. 관련해 설명하면서, 이제는 코루틴은 사용하지 않고 UniTask 로 많이들 넘어가서, UniTask 위주로 사용한다고 설명했다. Coroutine이 밀려나는 이유 간략하게 왜 Coroutine 을 사용하지 않게 된 건지 다시 알아보자. 반환형 사용 불가능 반환형이 사용 불가능하다. Coroutine 은 반드시 IEnuemrator 형을 반환형으로 가져야 하기 때문에, 내부 로직에 의해 산출된 결과물을 받아서 사용할 방법이 없다. 예외 처리 불가능 우리가 Coroutine 을 통해 비동기적으로 처리하고자 하는 작업들은 네트워크 통신, 파일 읽기처럼 오래 걸리는 작업도 포함되는데 예외처리가 불가능하면...문제가…
Открыть источник