UniTask & Những thứ liên quan
Minh Khoa
Author
🟦 1. UniTask là gì?
UniTask là thư viện async/await tối ưu cho Unity, được phát triển bởi Cysharp (cha đẻ MemoryPack, MessagePipe…).
Nó được tạo ra để thay thế hoàn toàn:
IEnumerator+StartCoroutineasync Task(C# tiêu chuẩn)- Các callback kiểu cũ
🟩 2. Vấn đề của Unity trước khi có UniTask
❌ (1) Coroutine chậm và khó kiểm soát
Coroutine có nhược điểm:
- Không bắt exception
- Không cancel đúng cách
- Không await được kết quả
- Không chạy đa luồng
- Không kết hợp tốt với async/await
- Không có return value
- Không tái sử dụng (phải tạo lại enumerator → GC)
- Mỗi yield tạo ra boxing → GC spike
Unity bản chất implement coroutine bằng mono scheduler → không tối ưu.
❌ (2) async Task của .NET quá nặng đối với Unity
async Task tạo rất nhiều allocation:
- Task object
- TaskCompletionSource
- Continuation delegate
- State machine
Unity GC yếu → dễ gây freeze micro-stutter.
❌ (3) Không có await cho Unity (await scene load, await animation, await frame)
Không thể viết kiểu:
await SceneManager.LoadSceneAsync("Game");
await UniTask.WaitForEndOfFrame();
await button.OnClickAsync();
Unity API hoàn toàn không có awaitable.
🟩 3. UniTask giải quyết toàn bộ vấn đề
⭐ UniTask KHÔNG ALLOCATION
Khác với async Task, UniTask:
- không tạo Task object
- không tạo heap allocation
- dùng struct-based awaiter
- chạy cực nhanh
Đây là lý do UniTask trở thành tiêu chuẩn cho Unity game performance.
⭐ Await mọi thứ trong Unity (điểm mạnh nhất)
UniTask thêm hàng loạt API mà Unity không có:
await UniTask.Delay(1000);
await UniTask.WaitForEndOfFrame();
await UniTask.WaitUntil(() => hp <= 0);
await transform.DOMove(...).ToUniTask();
await button.OnClickAsync();
await SceneManager.LoadSceneAsync("Battle").ToUniTask();
Workflow rõ ràng, sạch, không callback hell.
⭐ Chạy đa luồng thật sự (không như coroutine)
Coroutine chỉ chạy trên main thread.
UniTask chạy được trên thread pool, worker threads:
await UniTask.Run(() => HeavyCalculation());
→ Tách logic nặng khỏi main thread.
⭐ CancellationToken – thứ coroutine không có
Có thể cancel mọi async operation:
var cts = new CancellationTokenSource();
await DoSomethingAsync(cts.Token);
cts.Cancel();
Coroutine không thể cancel đẹp thế được.
⭐ Không cần StartCoroutine
UniTask dùng async/await:
await PlayerJumpAsync();
Không cần:
StartCoroutine(PlayerJump());
⭐ Nhẹ hơn Task, mạnh hơn Coroutine
=> UniTask = best of both worlds.
🟩 4. Nếu không có UniTask thì dùng gì?
Có 3 lựa chọn, nhưng đều THUA XA UniTask.
❌ 1. Dùng Coroutine thuần (truyền thống Unity)
Ví dụ:
StartCoroutine(LoadSceneRoutine());
Nhược điểm:
- không return value
- không bắt được exception
- không chạy background thread
- không await task async
- không phù hợp hệ thống lớn
- khó maintain
Chỉ dùng được cho prototype hoặc game nhỏ.
❌ 2. Dùng async Task của C#
Ví dụ:
await Task.Delay(1000);
Nhược điểm:
- ALLOCATION cực lớn
- GC nhiều
- Task overhead nặng
- Không có await Unity API
- Dễ lag frame
Unity game production không nên xài async Task để loop liên tục.
❌ 3. Dùng asset 3rd party như RSG Promises
Promise-based (JavaScript style), nhưng:
- nhiều GC
- khó maintain
- API phức tạp
- không unify được với async/await
Không còn phổ biến nữa.
🟦 5. Khi nào NÊN dùng UniTask trong game thực tế?
✔ Loading screen (await scene load)
✔ Nút button chờ người chơi (await OnClick)
✔ Chờ animation xong
✔ Chờ spine animation xong
✔ Chờ hiệu ứng DOTween (await tween.ToUniTask())
✔ Chờ API network trả về
✔ Save data async
✔ Multiplayer async
✔ Camera transitions
✔ Audio fade
✔ Spawn sequence logic
UniTask giúp code cực sạch:
Ví dụ code sản xuất:
await PlayIntroAsync();
await ShowPopupAsync();
await WaitForClickAsync();
await LoadStageAsync();
Flow siêu rõ ràng và đẹp.
🟦 6. Vậy, tại sao gần như mọi studio Unity đều dùng UniTask?
✔ Performance không GC
✔ Rất hợp với kiến trúc async/await C#
✔ Native integration với Unity
✔ API cực đầy đủ
✔ Chạy được trên cả thread pool
✔ Dùng cùng DOTween, Addressables, SceneManager, UI
Unity bản thân cũng bắt đầu chuyển sang mô hình async/await cho nhiều hệ thống → UniTask sẽ sống lâu dài.
🟥 7. Kết luận mạnh
🎯 UniTask mạnh vì:
- Không allocation (zero GC)
- Tối ưu hiệu năng hơn Task gấp nhiều lần
- Đầy đủ await cho Unity
- API cực hợp với workflow game
- Có cancellation
- Có multithreading
- Tích hợp tốt với DOTween, Addressables, UI, loading…
🎯 Nếu không có UniTask thì anh sẽ phải:
- Dùng Coroutine (yếu, cũ, khó maintain)
- Hoặc dùng async Task (nặng, lag, nhiều GC)
- Hoặc tự viết callback (xấu, khó debug)