当前位置:   article > 正文

UniTask异步解决方案_c# 异步事件 unitask

c# 异步事件 unitask

是一个高性能,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

  1. void Start()
  2. {
  3. StartCoroutine(waitting());
  4. }
  5. Ienumerator waitting()
  6. {
  7. yield return new waitForSeconds(2);
  8. }

  1. using System.Threading.Tasks;
  2. using UnityEngine;
  3. public class Zero :MonoBehaviour
  4. {
  5. async void Start()
  6. {
  7. await DealTest();
  8. }
  9. async Task<int> DealTest()
  10. {
  11. Debug.Log(Time.time);
  12. await Task.Delay(100);
  13. Debug.Log(Time.time);
  14. return 1;
  15. }
  16. }

延迟操作的API、Dealy方法、方法的重载及参数作用

UniTask.Delay                   延迟秒

UniTask.DelayFrame         延迟帧

UniTask.NextFrame          等待一帧

UniTask.Yield                    等待一帧,用于处理转回主线程用。yield之前再其他线程跑,yield之后回到主线程跑。

  1. Time.timeScale=0F;
  2. //等待时间,是否忽略时间缩放的影响(即便时间缩放为0但依然执行等待并向下执行,但是Time.time会受到影响),
  3. await UniTask.Delay(1000,true);

WaitUntil等方法

WaitUntil

//知道达到------才执行

//等到指定对象的参数发生变化时 参数目标 判断方法的委托 如果返回值变化的话 就发生变化

//WaitUntilValueChanged

//等到指定对象的参数发生变化时,才完成。

  1. using Cysharp.Threading.Tasks;
  2. using UnityEngine;
  3. public class Two : MonoBehaviour
  4. {
  5. public GameObject ball;
  6. void Start()
  7. {
  8. WaitUtilTest();
  9. WaitUntilValueTest();
  10. }
  11. void Update()
  12. {
  13. ball.transform.Translate(new Vector3(1,0,0)*Time.deltaTime);
  14. }
  15. async void WaitUtilTest()
  16. {
  17. await UniTask.WaitUntil(()=>isFarThanOne());//等到小球的x轴大于1后再执行方法的语句
  18. ball.GetComponent<Renderer>().material.color = Color.red;
  19. }
  20. public bool isFarThanOne()
  21. {
  22. if (ball.transform.position .x>1)
  23. {
  24. return true;
  25. }
  26. return false;
  27. }
  28. //如果小球的x轴变化就输出“小球值的变化”
  29. async void WaitUntilValueTest()
  30. {
  31. await UniTask.WaitUntilValueChanged(ball.transform,x=>x.position);
  32. Debug.Log("小球值的变化");
  33. }
  34. }

 WhenAll方法

当两个小球都达到1的时候,就执行等待函数代码

  1. using Cysharp.Threading.Tasks;
  2. using UnityEngine;
  3. public class Three : MonoBehaviour
  4. {
  5. public GameObject ball1;
  6. public GameObject ball2;
  7. void Start()
  8. {
  9. TestWhenAll();
  10. }
  11. void Update()
  12. {
  13. ball1.transform.Translate(new Vector3(1, 0, 0) * Time.deltaTime);
  14. ball2.transform.Translate(new Vector3(1, 0, 0) * Time.deltaTime * 0.5f);
  15. }
  16. async void TestWhenAll()
  17. {
  18. UniTask task1 = UniTask.WaitUntil(() => ball1.transform.position.x > 1);
  19. UniTask task2 = UniTask.WaitUntil(() => ball2.transform.position.x > 1);
  20. await UniTask.WhenAll(task1, task2);
  21. string str = $"ball1:{ball1.transform.position.x},ball2:{ball2.transform.position.x}";
  22. Debug.Log(str);
  23. }
  24. }

WhenAny方法

只有其中一个任务完成了就执行等待的方法

  1. using Cysharp.Threading.Tasks;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. public class Four : MonoBehaviour
  5. {
  6. public Button btn1;
  7. public Button btn2;
  8. public bool isClick1;
  9. public bool isClick2;
  10. void Start()
  11. {
  12. btn1.onClick.AddListener(() => Click1());
  13. btn2.onClick.AddListener(() => Click2());
  14. AllBtnClick();
  15. }
  16. public void Click1()
  17. {
  18. isClick1 = true;
  19. }
  20. public void Click2()
  21. {
  22. isClick2 = true;
  23. }
  24. async void AllBtnClick()
  25. {
  26. UniTask task1 = UniTask.WaitUntil(() => isClick1);
  27. UniTask task2 = UniTask.WaitUntil(() => isClick2);
  28. await UniTask.WhenAny(task1, task2);//uniTask 不能await两次
  29. Debug.Log("11");
  30. }
  31. }

Defer

UniTask.Void 参数异步委托 直接启动一个异步委托 不考虑其等待 无需加await

UniTask.Defer 用异步委托快速生成返回UniTask的异步方法,必须加await 才能执行

  1. void Start
  2. {
  3. UniTask.Void(async () =>
  4. {
  5. Debug.Log("start" + Time.frameCount);
  6. await UniTask.NextFrame();
  7. Debug.Log("end" + Time.frameCount);
  8. });
  9. }

  1. void Start()
  2. {
  3. await UniTask.Defer(async () =>
  4. {
  5. Debug.Log("start" + Time.frameCount);
  6. await UniTask.NextFrame();
  7. Debug.Log("end" + Time.frameCount);
  8. });
  9. }

协程与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,这两者的转换是无消耗的

  1. //动画序列
  2. await transform.DOMoveX(2,10);
  3. await transform.DOMoveX(5,20);
  4. //并行 并传递cancellation用于取消
  5. var ct=this.GetCancellationTokenOnDestroy();
  6. await UniTask.WhenAll(
  7. transform.DoMoveX(10,3).withCancellation(ct),
  8. transform.DoScale(10,3).withCancellation()
  9. );
  1. using Cysharp.Threading.Tasks;
  2. using System.Collections;
  3. using UnityEngine;
  4. public class Six : MonoBehaviour
  5. {
  6. async void Start()
  7. {
  8. StartCoroutine(CorotineTest());
  9. //实现协程等待
  10. await CorotineTest();
  11. }
  12. IEnumerator CorotineTest()
  13. {
  14. Debug.Log("start");
  15. yield return new WaitForSeconds(1);
  16. Debug.Log("end");
  17. }
  18. }
  1. using Cysharp.Threading.Tasks;
  2. using System;
  3. using System.Collections;
  4. using UnityEngine;
  5. public class Six : MonoBehaviour
  6. {
  7. async void Start()
  8. {
  9. StartCoroutine(CorotineTest1());
  10. }
  11. IEnumerator CorotineTest1()
  12. {
  13. Debug.Log("start");
  14. //使用这个方法将UniTask组件转化成协程
  15. //如果你想将异步转换成协程,你可以使用.ToCoroutine(),如果你只想允许使用携程系统,这很有用。
  16. yield return UniTask.Delay(TimeSpan.FromSeconds(1)).ToCoroutine();
  17. Debug.Log("end");
  18. }
  19. }

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/87429
推荐阅读
  

闽ICP备14008679号