Under Construction

Prometheus Lab

Portfolio & Resources

Back to Blog
Unity9 min2 views

UniTask & Những thứ liên quan

Author

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 + StartCoroutine
  • async 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 schedulerkhô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

image.png=> UniTask = best of both worlds.


🟩 4. Nếu không có UniTask thì dùng gì?

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)