赞
踩
是一个高性能,0GC的async/await异步方案
协程缺点:
依赖monobehaviour
不能进行异常处理
方法返回值获取困难
c#原生Task:
优点:
不依赖monobehaviour
可以处理异常
缺点:
Task消耗大,设计跨线程操作
uniTask
优点:
继承c#的task优点
基于值类型解决方案,0GC
默认使用主协程
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
延时操作:Delay DelayFrame Yield NextFrame WaitForEndOfFrame
等待操作: Wait Until Wait Until Value Changed
条件操作: When All When Any
异步委托生成UniTask及相关的封装: UniTask.Void UniTask.Defer UniTask.Lazy
取消:CancellationToken GetCancellationTokenOnDeatory()
异常处理:Try Catch SuppressCancellationThrow
超时处理:取消的变种,通过 CancellationTokenSouce.CancelAfterSlim(TimeSpan)设置超时并将CancellationToken 传递给异步方法
Forget()
事件处理:
1.异步事件 Lamaba 表达式注册 使用 UniTask.Action 或 UniTask.UnityAction
2.UGUI 事件转换为可等待事件
AsAsyncEnumerable
3.MonoBehaviour 消息事件都可以转换异步流
异步Linq
异步迭代器
响应式组件
协程和task
- void Start()
- {
- StartCoroutine(waitting());
- }
- Ienumerator waitting()
- {
- yield return new waitForSeconds(2);
- }
- using System.Threading.Tasks;
- using UnityEngine;
-
- public class Zero :MonoBehaviour
- {
- async void Start()
- {
- await DealTest();
- }
- async Task<int> DealTest()
- {
- Debug.Log(Time.time);
- await Task.Delay(100);
- Debug.Log(Time.time);
- return 1;
- }
- }
延迟操作的API、Dealy方法、方法的重载及参数作用
UniTask.Delay 延迟秒
UniTask.DelayFrame 延迟帧
UniTask.NextFrame 等待一帧
UniTask.Yield 等待一帧,用于处理转回主线程用。yield之前再其他线程跑,yield之后回到主线程跑。
- Time.timeScale=0F;
- //等待时间,是否忽略时间缩放的影响(即便时间缩放为0但依然执行等待并向下执行,但是Time.time会受到影响),
- await UniTask.Delay(1000,true);
WaitUntil等方法
WaitUntil
//知道达到------才执行
//等到指定对象的参数发生变化时 参数目标 判断方法的委托 如果返回值变化的话 就发生变化
//WaitUntilValueChanged
//等到指定对象的参数发生变化时,才完成。
- using Cysharp.Threading.Tasks;
- using UnityEngine;
-
- public class Two : MonoBehaviour
- {
- public GameObject ball;
- void Start()
- {
- WaitUtilTest();
- WaitUntilValueTest();
- }
- void Update()
- {
- ball.transform.Translate(new Vector3(1,0,0)*Time.deltaTime);
- }
- async void WaitUtilTest()
- {
-
- await UniTask.WaitUntil(()=>isFarThanOne());//等到小球的x轴大于1后再执行方法的语句
- ball.GetComponent<Renderer>().material.color = Color.red;
- }
- public bool isFarThanOne()
- {
- if (ball.transform.position .x>1)
- {
- return true;
- }
- return false;
- }
- //如果小球的x轴变化就输出“小球值的变化”
- async void WaitUntilValueTest()
- {
- await UniTask.WaitUntilValueChanged(ball.transform,x=>x.position);
- Debug.Log("小球值的变化");
- }
- }
WhenAll方法
当两个小球都达到1的时候,就执行等待函数代码
- using Cysharp.Threading.Tasks;
- using UnityEngine;
-
- public class Three : MonoBehaviour
- {
- public GameObject ball1;
- public GameObject ball2;
- void Start()
- {
- TestWhenAll();
- }
- void Update()
- {
- ball1.transform.Translate(new Vector3(1, 0, 0) * Time.deltaTime);
- ball2.transform.Translate(new Vector3(1, 0, 0) * Time.deltaTime * 0.5f);
-
- }
- async void TestWhenAll()
- {
- UniTask task1 = UniTask.WaitUntil(() => ball1.transform.position.x > 1);
- UniTask task2 = UniTask.WaitUntil(() => ball2.transform.position.x > 1);
-
- await UniTask.WhenAll(task1, task2);
- string str = $"ball1:{ball1.transform.position.x},ball2:{ball2.transform.position.x}";
- Debug.Log(str);
- }
- }
WhenAny方法
只有其中一个任务完成了就执行等待的方法
- using Cysharp.Threading.Tasks;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class Four : MonoBehaviour
- {
- public Button btn1;
- public Button btn2;
- public bool isClick1;
- public bool isClick2;
- void Start()
- {
- btn1.onClick.AddListener(() => Click1());
- btn2.onClick.AddListener(() => Click2());
- AllBtnClick();
- }
- public void Click1()
- {
- isClick1 = true;
- }
- public void Click2()
- {
- isClick2 = true;
- }
- async void AllBtnClick()
- {
- UniTask task1 = UniTask.WaitUntil(() => isClick1);
- UniTask task2 = UniTask.WaitUntil(() => isClick2);
-
- await UniTask.WhenAny(task1, task2);//uniTask 不能await两次
- Debug.Log("11");
- }
- }
Defer
UniTask.Void 参数异步委托 直接启动一个异步委托 不考虑其等待 无需加await
UniTask.Defer 用异步委托快速生成返回UniTask的异步方法,必须加await 才能执行
- void Start
- {
- UniTask.Void(async () =>
- {
- Debug.Log("start" + Time.frameCount);
- await UniTask.NextFrame();
- Debug.Log("end" + Time.frameCount);
- });
- }
- void Start()
- {
- await UniTask.Defer(async () =>
- {
- Debug.Log("start" + Time.frameCount);
- await UniTask.NextFrame();
- Debug.Log("end" + Time.frameCount);
- });
- }
协程与uniTask的转换
一些需要用到等待的unity对戏提供GetAwaiter()功能,从而拿到Awaiter对戏就可以进行await了。UniTask已经对各种各样的unity对戏进行了GetAwaiter的扩展。
1.Coroutine的等待及UniTask的转换
2.AsyncOperation的等待 如场景异步加载 资源异步加载 网络请求
3.UGUI的部分响应方法等待 如鼠标点击事件
4.MonoBehaviour的部分功能可以等待 如触发器
5.部分插件的扩展DOTween
Task -> UniTask : 使用AsUniTask
UniTask -> UniTask : 使用AsAsyncUnitUniTask
UniTask -> UniTask : 使用AsUniTask,这两者的转换是无消耗的
- //动画序列
- await transform.DOMoveX(2,10);
- await transform.DOMoveX(5,20);
- //并行 并传递cancellation用于取消
- var ct=this.GetCancellationTokenOnDestroy();
- await UniTask.WhenAll(
- transform.DoMoveX(10,3).withCancellation(ct),
- transform.DoScale(10,3).withCancellation()
- );
- using Cysharp.Threading.Tasks;
- using System.Collections;
- using UnityEngine;
-
- public class Six : MonoBehaviour
- {
- async void Start()
- {
- StartCoroutine(CorotineTest());
- //实现协程等待
- await CorotineTest();
- }
-
- IEnumerator CorotineTest()
- {
- Debug.Log("start");
- yield return new WaitForSeconds(1);
- Debug.Log("end");
- }
- }
- using Cysharp.Threading.Tasks;
- using System;
- using System.Collections;
-
- using UnityEngine;
-
- public class Six : MonoBehaviour
- {
- async void Start()
- {
- StartCoroutine(CorotineTest1());
-
-
- }
-
-
- IEnumerator CorotineTest1()
- {
- Debug.Log("start");
- //使用这个方法将UniTask组件转化成协程
- //如果你想将异步转换成协程,你可以使用.ToCoroutine(),如果你只想允许使用携程系统,这很有用。
- yield return UniTask.Delay(TimeSpan.FromSeconds(1)).ToCoroutine();
- Debug.Log("end");
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。