기존 C#의 Task는 무겁기도 하고 GC 할당이 계속 발생해서 UniTask를 사용했습니다.
구조체(struct) 기반이라 메모리 할당이 거의 없어요!
일단 패키지부터 설치해야겠죠?
Window -> Package Manager -> Add package from git URL 누르고 아래 주소 입력!
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask

아래 링크 넣어서 다운로드
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
원래 Coroutine이랑 Action(콜백) 써서 비동기 통신을 구현했었는데, 이게 가독성이 진짜 안 좋아서 UniTask로 싹 바꿔버렸습니다. 그리고 공부할겸! 활용해봤습니다~
[Before] 기존 코드: 코루틴 + 콜백
결과값을 바로 return 못하고 callback으로 넘겨줘야 하는게 제일 불편함 ㅠㅠ
// IEnumerator 반환, 결과는 Action 콜백으로 넘겨줌
public IEnumerator MostSimilarty(string inputWord, int num, Action<List<string>> callback)
{
// ... (중략) ...
using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
{
// [기존 방식] 여기서 yield return으로 대기
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
// ... 데이터 파싱 ...
// [단점] 값을 직접 리턴 못하고 콜백 함수 호출해야 함
callback(responseData.result);
}
else
{
callback(new List<string> { "요청 실패" });
}
}
}
[After] 개선된 코드: UniTask + Async/Await
async 키워드 붙이고 결과값을 바로 return 받을 수 있어서 완전 직관적임!
using Cysharp.Threading.Tasks; // 필수!
// async 키워드 사용, List<string>을 직접 반환!
public async UniTask<List<string>> MostSimilarty(string inputWord, int num)
{
// ... (중략) ...
using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
{
// [개선] await로 기다림
await request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
// ... 데이터 파싱 ...
// [장점] 그냥 바로 return 때리면 됨
return responseData.result;
}
else
{
return new List<string> { "요청 실패" };
}
}
}
[Before] 기존: 콜백 지옥 (계단식 코드)
StartCoroutine 안에 람다식 (result) => { ... } 들어가니까 들여쓰기가 계속 깊어짐;;
public void OnShowSimilarWord()
{
// ... 생략 ...
// [단점] StartCoroutine + 람다식 콜백 = 가독성 떨어짐
StartCoroutine(pythonConnectManager.MostSimilarty(answerWord, 5, (result) =>
{
loading?.StopAnim();
// --- 여기서부터 결과 처리 로직 ---
if (result == null) { ... }
// 로직이 길어질수록 계속 들여쓰기 해야함 ㅠㅠ
resultText.text = $"관련 단어 : {result[idx]}";
}));
}
[After] 개선: 선형적인 코드
// async void로 변경 (유니티 이벤트 함수용)
public async void OnShowSimilarWord()
{
// ... 생략 ...
// [장점] await로 결과값 바로 받아옴! (코루틴 삭제)
List<string> result = await pythonConnectManager.MostSimilarty(answerWord, 5);
loading?.StopAnim();
// --- 들여쓰기 없이 바로 로직 작성 가능 ---
if (result == null) { ... }
resultText.text = $"관련 단어 : {result[idx]}";
}
네트워크만 바꾸긴 아쉬워서 씬 로딩도 바꿨습니당.
보통 로딩바 구현할 때 StartCoroutine이랑 yield return null 쓰잖아요? 근데 yield return null이 미세하게 가비지를 만든다는 사실.. UniTask 쓰면 이것도 해결된다고 하더라구요
[Before]
IEnumerator LoadRoutine(string targetScene)
{
AsyncOperation op = SceneManager.LoadSceneAsync(targetScene);
op.allowSceneActivation = false;
while (!op.isDone)
{
yield return null; // 매 프레임 가비지 생성 가능성 있음
// ... 진행률 계산 로직 ...
}
}
[After]
// Start에서 바로 비동기 함수 호출 가능!
async void Start()
{
await LoadSceneAsync("TargetScene");
}
async UniTask LoadSceneAsync(string targetScene)
{
await UniTask.Yield(); // 첫 프레임 대기
AsyncOperation op = SceneManager.LoadSceneAsync(targetScene);
op.allowSceneActivation = false;
while (!op.isDone)
{
// [핵심] struct 기반이라 메모리 할당 없음 (Zero Allocation)
await UniTask.Yield();
// ... 진행률 계산 (기존과 동일) ...
float raw = Mathf.Clamp01(op.progress / 0.9f);
loadingUI?.SetProgress(raw);
if (raw >= 1f)
{
op.allowSceneActivation = true;
break;
}
}
}
Start()를 async void로 바꾸고 UniTask.Yield()를 쓰면 끗
💡 UniTask의 효과!
가독성 떡상: 콜백 지옥 탈출하고 코드가 깔끔해짐
메모리 절약: yield return null 대신 UniTask.Yield() 써서 GC 방어
예외 처리: 코루틴에선 안되던 try-catch가 먹힘