UniTask는 기존의 코루틴보다 더 나은 비동기 처리를 가능하게 해주는 강력한 라이브러리입니다. 구체적인 장점과 사용 예시를 통해 UniTask의 유용성을 알아보겠습니다.
UniTask를 사용하게 된 이유:
- 코루틴의 예외 처리 제한: 코루틴은 try-catch로 예외 처리를 할 수 없어서 안정성이 떨어집니다.
- 코루틴의 리턴 타입 제한: 코루틴은 리턴 타입이 없어 실행 결과를 리턴하려면 콜백을 사용해야 합니다. 이로 인해 복잡한 콜백 지옥이 발생할 수 있습니다.
- Task의 성능 문제: C#의 async Task는 힙 할당으로 인해 가비지 생성이 많아 잦은 호출이 어렵습니다. 하지만 UniTask는 struct 기반이어서 가비지 생성 문제가 없습니다.
- 선형적인 코드 흐름: UniTask를 사용하면 콜백 없이 선형적으로 코드가 작성되어 코드가 훨씬 직관적이고 관리하기 쉬워집니다.
- 유니티 에디터 툴에서의 활용: EditorCoroutines와 같이 유니티 에디터 스크립트 작성 시에도 UniTask를 사용하면 코드 관리가 용이합니다.
코루틴과 UniTask 비교 예시
아래 예시에서는 유저의 레벨을 가져오는 비동기 작업을 코루틴과 UniTask로 구현한 예시를 비교합니다.
코루틴 예시:
코루틴을 사용하여 유저 레벨을 가져오는 코드입니다. 콜백을 사용하고 있어 가독성이 떨어지고, 예외 처리가 불가능합니 다.
IEnumerator GetUserLevel(string id, System.Action<int> callback)
{
// 예외 처리 불가
var req = UnityWebRequest.Get($"https://.../api/{id}");
yield return req.SendWebRequest();
if (req.result != UnityWebRequest.Result.Success)
{
Debug.LogError(req.error);
callback(-1);
}
else
{
callback(int.Parse(req.downloadHandler.text));
}
}
void tast()
{
StartCoroutine(GetUserLevel("id", id =>
{
Debug.Log($"User Level: {id}");
}));
}
이 예제는 웹 서버에서 유저의 레벨을 가져오는 코드입니다. 코루틴을 사용하면 콜백을 사용해야 하며, 예외 처리가 불가능한 단점이 있습니다.
UniTask 예시
UniTask를 사용하여 동일한 작업을 수행하는 코드입니다. try-catch로 예외 처리를 할 수 있으며, 코드 흐름이 선형적이고 직관적입니다.
async UniTask<int> GetUserLevelAsync(string userName)
{
try
{
var req = UnityWebRequest.Get($"https://.../user/{userName}");
await req.SendWebRequest();
if (req.result != UnityWebRequest.Result.Success)
{
Debug.LogError(req.error);
return -1;
}
return int.Parse(req.downloadHandler.text);
}
catch (Exception e)
{
Debug.LogError($"Exception: {e.Message}");
return -1;
}
}
async void Logic()
{
try
{
int level = await GetUserLevelAsync("user1");
Debug.Log($"User Level: {level}");
}
catch (Exception e)
{
Debug.LogError($"Unhandled Exception: {e.Message}");
}
}
UniTask를 사용하면 코드는 더 직관적이고 예외 처리가 가능해집니다. 코드의 흐름이 명확해지고 가독성이 좋아집니다.
UniTask의 특징
UniTask는 다음과 같은 특징을 가지고 있습니다:
- Zero Allocation: UniTask는 struct 기반으로 힙 할당이 없어 가비지 생성을 줄입니다.
- 유니티의 Async Operations 지원: 어드레서블 같은 비동기 작업을 await으로 기다릴 수 있습니다.
- 유니티 메인 쓰레드 기반: UniTask는 유니티의 메인 쓰레드에서 작동해 WebGL/WASM에서도 사용할 수 있습니다.
- Cancellation Token 지원: 작업 취소를 간단하게 관리할 수 있으며, 오브젝트가 삭제될 때 자동으로 작업을 취소할 수 있습니다.
- 기존 Task와의 호환성: 기존 C# Task, ValueTask와 높은 호환성을 보입니다.
비동기 UI 애니메이션 예시:
UniTask와 DoTween을 사용하여 비동기적으로 UI 애니메이션을 처리하는 예시입니다. await를 사용해 순서대로 실행하며, 필요하지 않은 부분에서는 await를 생략하여 비동기적으로 실행합니다.
async UniTask StartTitleAnimation()
{
// 초기화면 대기
await UniTask.Delay(1500);
// 텍스트 상태 초기화
titleText.rectTransform.anchoredPosition = new Vector2(0, titleText.rectTransform.sizeDelta.y / 2);
titleText.text = "Loading...";
titleText.gameObject.SetActive(true);
await titleText.rectTransform.DOAnchorPosY(-330f, 0.5f).SetEase(Ease.OutCirc);
await UniTask.Delay(700);
// 텍스트 상태 변경
titleText.text = "The Black";
titleText.fontSize = 100;
titleText.transform.localScale = new Vector3(2, 2, 2);
// 텍스트 커짐->작아짐
await titleText.transform.DOScale(1, 0.5f).SetEase(Ease.OutBack);
// pressAnyKey는 대기하지 않음
pressAnyKeyText.transform.localScale = new Vector3(2, 2, 2);
pressAnyKeyText.gameObject.SetActive(true);
pressAnyKeyText.transform.DOScale(1, 0.35f).SetEase(Ease.OutBack);
// 트윈 무한 반복
await titleText.transform.DOScale(1.1f, 2).SetLoops(-1, LoopType.Yoyo).SetEase(Ease.InOutQuad);
}
void Start()
{
StartTitleAnimation().Forget();
}
비동기 작업 취소 (Cancellation) 예시:
오브젝트가 삭제되거나 씬이 변경될 때 자동으로 비동기 작업을 중단할 수 있도록 Cancellation Token을 사용하는 방법입니다.
public async UniTaskVoid WhileTest()
{
var cancellationToken = this.GetCancellationTokenOnDestroy();
while (true)
{
await UniTask.Yield(cancellationToken: cancellationToken);
Debug.Log(Time.realtimeSinceStartup);
}
}
public async UniTask Start()
{
WhileTest();
}
private void OnDestroy()
{
Debug.Log("오브젝트를 삭제했습니다. 더이상 비동기가 실행되면 안됩니다.");
}
이 예시에서는 UniTask의 CancellationToken을 사용해 오브젝트가 삭제되었을 때 자동으로 비동기 작업을 중단하도록 설정하였습니다. 이를 통해 불필요한 비동기 작업을 방지하고 리소스를 효율적으로 사용할 수 있습니다.
UniTask는 기존의 코루틴을 대체하여 비동기 작업을 더욱 효율적으로 관리할 수 있게 해주는 강력한 라이브러리입니다. 특히 복잡한 비동기 로직을 직관적으로 관리할 수 있고, 가비지 생성 문제를 줄여 성능 최적화에 도움을 줍니다.
'Unity' 카테고리의 다른 글
[Unity] WebGl환경 iis로 Websocket 통신 방법 Javascript NativePlugin (4) | 2024.12.27 |
---|---|
[Unity] InputSystem 사용방법(PlayerInputComponent와 Generate C# Class) (0) | 2024.12.27 |
[Unity] JobSystem(2) NativeContainer와 TransformAccessArray (1) | 2024.09.06 |
[Unity] JobSystem(1) 특징과 인터페이스 종류 (0) | 2024.09.06 |
[Unity] Unity 메모리 및 GC 최적화 ( 정리중 ) (0) | 2024.08.30 |