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

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");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值