UniTask
链接:UniTask/src/UniTask/Assets/Plugins/UniTask at master · Cysharp/UniTask · GitHub
特性 | 传统 Task | UniTask |
---|---|---|
GC 分配 | 每次 await 产生 GC | 零 GC |
时间系统 | 依赖系统时钟 | 自动同步 Time.timeScale |
线程安全 | 需手动回主线程 | 默认在主线程执行 |
性能 | 较慢 | 快 2-5 倍 |
向上优化Task,向下兼容协程。
命名空间
using Cysharp.Threading.Tasks;
与原生Task的API对比
.NET 类型 | UniTask 类型 |
---|---|
IProgress<T> | --- |
CancellationToken | --- |
CancellationTokenSource | --- |
Task/ ValueTask | UniTask |
Task<T>/ ValueTask<T> | UniTask<T> |
async void | async UniTaskVoid |
+= async () => { } | UniTask.Void, UniTask.Action, UniTask.UnityAction |
--- | UniTaskCompletionSource |
TaskCompletionSource<T> | UniTaskCompletionSource<T>/ AutoResetUniTaskCompletionSource<T> |
ManualResetValueTaskSourceCore<T> | UniTaskCompletionSourceCore<T> |
IValueTaskSource | IUniTaskSource |
IValueTaskSource<T> | IUniTaskSource<T> |
ValueTask.IsCompleted | UniTask.Status.IsCompleted() |
ValueTask<T>.IsCompleted | UniTask<T>.Status.IsCompleted() |
new Progress<T> | Progress.Create<T> |
CancellationToken.Register(UnsafeRegister) | CancellationToken.RegisterWithoutCaptureExecutionContext |
CancellationTokenSource.CancelAfter | CancellationTokenSource.CancelAfterSlim |
Channel.CreateUnbounded<T>(false){ SingleReader = true} | Channel.CreateSingleConsumerUnbounded<T> |
IAsyncEnumerable<T> | IUniTaskAsyncEnumerable<T> |
IAsyncEnumerator<T> | IUniTaskAsyncEnumerator<T> |
IAsyncDisposable | IUniTaskAsyncDisposable |
Task.Delay | UniTask.Delay |
Task.Yield | UniTask.Yield |
Task.Run | UniTask.RunOnThreadPool (不推荐,考虑是否能用UniTask.Create) |
--- | UniTask.Create |
--- | UniTask.Defer |
--- | UniTask.Lazy |
Task.WhenAll | UniTask.WhenAll |
Task.WhenAny | UniTask.WhenAny |
Task.CompletedTask | UniTask.CompletedTask |
Task.FromException | UniTask.FromException |
Task.FromResult | UniTask.FromResult |
Task.FromCanceled | UniTask.FromCanceled |
Task.ContinueWith | UniTask.ContinueWith |
TaskScheduler.UnobservedTaskException | UniTaskScheduler.UnobservedTaskException |
常用API
UniTask.Create
创建:该方法被调用的时候,立即创建一个新的UniTask
执行:UniTask在Create()被调用的那一刻就开始执行了
UniTask task = UniTask.Create(
async ()=>
{
Debug.Log("Create");
await UniTask.Delay(1000);
Debug.Log("Complete");
});
UniTask.Defer
创建:将UniTask创建延迟到await的时机
执行:只能await一次,但比Lazy轻量
UniTask task = UniTask.Defer(
async () =>
{
Debug.Log("Defer");
await UniTask.Delay(1000);
Debug.Log("Complete");
}
);
await defer;
UniTask.Lazy
创建:将UniTask创建延迟到await的时机
执行:创建AsyncLazy,AsyncLazy.Task可以被await任意次数,比Defer的成本更高
AsyncLazy asyncLazy = UniTask.Lazy(
async () =>
{
Debug.Log("AsyncLazy");
await UniTask.Delay(1000);
Debug.Log("Complete");
}
);
await asyncLazy.Task;
await asyncLazy.Task;
UniTask与UniTaskVoid
场景特征 | 使用 UniTask | 使用 UniTaskVoid |
---|---|---|
需要等待结果 | ✅ (如 await GetPlayerData() ) | ❌ |
需要返回值 | ✅ (如 return score ) | ❌ |
UI 事件触发 | ❌ | ✅ (避免 async void 风险) |
长时间后台任务 | ✅ (结合 CancellationToken ) | ✅ (需显式绑定生命周期) |
高频触发(如每帧) | ❌ (会产生 Task 实例) | ✅ (零 GC 压力) |
DOTween UniTask化
对Tween或Sequence动画可进行异步等待
public static class DOTweenExtensions {
public static UniTask AwaitForComplete(this Tween tween, CancellationToken cancellationToken = default) {
var tcs = new UniTaskCompletionSource();
try {
tween.OnComplete(() => tcs.TrySetResult());
tween.OnKill(() => tcs.TrySetCanceled());
cancellationToken.Register(() => tween.Kill());
}
catch (Exception e) {
Debug.LogError($"Tween AwaitForComplete Error: {e}");
tcs.TrySetException(new Exception($"DOTween AwaitForComplete Error: {e}"));
}
return tcs.Task;
}
}
// 使用方法:
try {
await sequence.AwaitForComplete(cancelToken);
}
catch (OperationCanceledException) {
Debug.Log("Tween Canceled");
}
catch (Exception ex) {
Debug.LogError($"Tween Get Error: {ex}");
}
Spine UniTask化
仅针对最常用的Spine.AnimationState.SetAnimation方法进行UniTask化。
该方法对循环动画的处理可自行定义。
本代码仅考虑了单轨道动画,对多轨道动画的实际表现未知。
public static class SpineExtensions {
public static UniTask AwaitForComplete(this TrackEntry entry, Spine.AnimationState state = null, CancellationToken cancellationToken = default) {
var tcs = new UniTaskCompletionSource();
try {
if (!entry.Loop) {
entry.Complete += _ => tcs.TrySetResult();
entry.End += _ => tcs.TrySetCanceled();
}
else {
entry.End += _ => tcs.TrySetResult();
}
if (cancellationToken != default && state != null) {
cancellationToken.Register(() => state.ClearTrack(entry.TrackIndex));
}
}
catch (Exception e) {
Debug.LogError($"TrackEntry AwaitForComplete Error: {e}");
tcs.TrySetException(new Exception($"Spine AwaitForComplete Error: {e}"));
}
return tcs.Task;
}
}
// 使用方法:
try {
TrackEntry entry = skeleton_animation.state.SetAnimation(0, animationName, loop);
await entry.AwaitForComplete(skeleton_animation.state, cancelToken);
}
catch (OperationCanceledException) {
Debug.Log("Animation Canceled");
}
catch (Exception ex) {
Debug.LogError($"Animation Get Error: {ex}");
}
Task UniTask化
*.AsUniTask()
参考文章
https://zhuanlan.zhihu.com/p/572670728https://zhuanlan.zhihu.com/p/572670728spine-unity 运行时文档
https://zh.esotericsoftware.com/spine-unity