UniTask 异步任务

文章目录

  • 前言
  • 一、UniTask是什么?
  • 二、使用步骤
  • 三、常用的UniTask API和示例
    • 1.编写异步方法
    • 2.处理异常
    • 3.延迟执行
    • 4.等待多个UniTask或者一个UniTas完成
    • 5.异步加载资源示例
    • 6.手动控制UniTask的完成状态
    • 7.UniTask.Lazy延迟任务的创建
    • 8.后台线程切换Unity主线程
    • 9.不要返回值
    • 10.缓存UniTask的结果
    • 11.指定异步操作阶段执行
    • 12.创建完成的UniTask
    • 13.UniTask.ToCoroutine转换协程
    • 14.异步迭代集合
    • 15. 异步判断
    • 16. uniTask的取消
    • 17.网络请求加载图片
    • 18.异步判断按钮是否被双击
    • 19.每次点击修改按钮不同的文本
  • 四、 总结

前言

随着Unity游戏开发的流行,异步编程变得越来越重要。UniTask是一个轻量级的异步编程库,它为Unity开发者提供了更高效的编程方式。本文将介绍UniTask的基础内容和一些常用的API,以及它们的使用示例。


一、UniTask是什么?

UniTask是一个专为Unity设计的异步编程库,它提供了类似于C#的Taskasync/await的功能,但是更加适合Unity的执行模型和生命周期。

二、使用步骤

UniTaskGit地址
UniTask中文文档地址

首先,需要在Unity项目中安装UniTask。可以通过Unity Package Manager(UPM)安装,或者直接从GitHub下载源码

本文介绍从GitHub下载
在这里插入图片描述

在这里插入图片描述


三、常用的UniTask API和示例

1.编写异步方法

使用UniTask时,可以像编写普通的异步方法一样使用async关键字和UniTask返回类型

// 示例:一个简单的异步加载场景的方法
async UniTask LoadSceneAsync(string sceneName)
{
    // 使用UniTask的场景加载方法
    await SceneManager.LoadSceneAsync(sceneName).ToUniTask();
    // 场景加载完成后的操作
    Debug.Log("Scene loaded");
}

2.处理异常

UniTask也支持异常处理,可以使用try/catch块来捕获异步方法中的异常

// 示例:带有异常处理的异步方法
async UniTask DoSomethingAsync()
{
    try
    {
        // 可能会抛出异常的操作
        await SomeRiskyOperation().ToUniTask();
    }
    catch (Exception ex)
    {
        // 处理异常
        Debug.LogError(ex.Message);
    }
}

3.延迟执行

UniTask.Delay: 延迟执行,类似于Task.Delay

// 延迟执行示例
async UniTask DelayedOperation()
{
    await UniTask.Delay(TimeSpan.FromSeconds(5));
    Debug.Log("Operation executed after 5 seconds");
}

4.等待多个UniTask或者一个UniTas完成

UniTask.WhenAll: 等待多个UniTask完成,类似于Task.WhenAll

// 并行执行多个任务示例
async UniTask RunMultipleTasks()
{
    // 创建多个任务
    var task1 = DoTask1Async();
    var task2 = DoTask2Async();
    
    // 等待所有任务完成
    await UniTask.WhenAll(task1, task2);
    
    Debug.Log("全部任务完成");
}
async void RunSingleTask()
{
    UniTask task1 = UniTask.WaitUntil(() => isClick1);
    UniTask task2 = UniTask.WaitUntil(() => isClick2);
    await UniTask.WhenAny(task1, task2);
    Debug.Log("一个任务完成");
}

5.异步加载资源示例

// 异步加载资源示例
async UniTask<Texture> LoadTextureAsync(string url)
{
    using (var request = UnityWebRequestTexture.GetTexture(url))
    {
        await request.SendWebRequest().ToUniTask();
        if (request.isNetworkError || request.isHttpError)
        {
            Debug.LogError(request.error);
            return null;
        }
        return DownloadHandlerTexture.GetContent(request);
    }
}

6.手动控制UniTask的完成状态

UniTaskCompletionSource允许你手动控制UniTask的完成状态。这在需要等待非异步方法完成的情况下非常有用。

UniTaskCompletionSource<bool> ucs = new UniTaskCompletionSource<bool>();

// 在某个事件发生时完成任务
void OnSomeEvent()
{
    ucs.TrySetResult(true);
}

// 等待事件完成
async UniTask WaitSomeEventAsync()
{
    await ucs.Task;
    Debug.Log("Event occurred");
}

7.UniTask.Lazy延迟任务的创建

UniTask.Lazy可以延迟任务的创建,直到真正需要执行任务时才会创建。

// 示例:延迟创建任务
UniTask<string> lazyTask = UniTask.Lazy(async () =>
{
    await UniTask.Delay(1000);
    return "Result after delay";
});

// 在需要结果时等待任务
string result = await lazyTask;
Debug.Log(result);

8.后台线程切换Unity主线程

在需要从后台线程切换回Unity主线程时,可以使用UniTask.SwitchToMainThread

// 示例:在后台线程上执行操作,然后切换回主线程
async UniTask DoOperationAndSwitchBack()
{
    // 在后台线程上执行耗时操作
    await UniTask.Run(() => SomeHeavyOperation());
    
    // 切换回主线程
    await UniTask.SwitchToMainThread();
    
    // 在主线程上执行Unity相关操作
    Debug.Log("Back on main thread");
}

9.不要返回值

当你不需要关心异步方法的返回值时,可以使用UniTaskVoid。这对于触发事件或执行不需要返回结果的后台操作非常有用。

// 示例:一个不返回任何结果的异步方法
async UniTaskVoid PerformBackgroundOperation()
{
    // 执行一些后台操作
    await UniTask.Delay(1000);
    Debug.Log("Background operation completed");
}

10.缓存UniTask的结果

如果你想要缓存一个UniTask的结果以供后续使用,可以使用UniTask<T>.Preserve方法。

// 示例:缓存异步操作的结果
UniTask<int> originalTask = CalculateValueAsync();
UniTask<int> preservedTask = originalTask.Preserve();

// 在不同的地方使用缓存的结果
int result1 = await preservedTask;
int result2 = await preservedTask;

11.指定异步操作阶段执行

PlayerLoopTiming枚举允许你指定异步操作应该在Unity的哪个阶段执行。这可以帮助你更精确地控制代码的执行时间。

// 示例:在FixedUpdate阶段执行异步操作
async UniTask PerformOperationInFixedUpdate()
{
    await UniTask.Yield(PlayerLoopTiming.FixedUpdate);
    // 在FixedUpdate阶段执行的代码
    Debug.Log("This is executed in FixedUpdate");
}

12.创建完成的UniTask

当你已经有了结果,并且想要创建一个已经完成的UniTask时,可以使用UniTask.FromResult

// 示例:创建一个已经完成的UniTask
UniTask<int> completedTask = UniTask.FromResult(42);

13.UniTask.ToCoroutine转换协程

如果你需要将UniTask与旧的协程系统兼容,可以使用UniTask.ToCoroutine将其转换为协程。

// 示例:将UniTask转换为协程
IEnumerator MyCoroutine()
{
    yield return LoadSceneAsync("MyScene").ToCoroutine();
}

14.异步迭代集合

UniTask支持异步枚举器,这允许你使用await foreach来异步迭代集合。

// 示例:使用异步枚举器迭代集合
async UniTask ProcessItemsAsync(IAsyncEnumerable<int> items)
{
    await foreach (var item in items)
    {
        Debug.Log(item);
    }
}

15. 异步判断

UniTask.WaitUntilUniTask.WaitWhile这些方法允许你等待直到某个条件为真或为假。

// 示例:等待直到条件为真
async UniTask WaitUntilConditionMet()
{
    await UniTask.WaitUntil(() => someCondition);
    Debug.Log("Condition met");
}

// 示例:等待直到条件为假
async UniTask WaitWhileConditionMet()
{
    await UniTask.WaitWhile(() => someCondition);
    Debug.Log("Condition no longer met");
}

16. uniTask的取消

通过 CancellationTokenSource完成UniTask的取消


public class Test : MonoBehaviour
{
    private CancellationTokenSource cts;


    void Start()
    {
        cts = new CancellationTokenSource();

        StartCount();

        cts.CancelAfter(TimeSpan.FromSeconds(10));
    }

    private async UniTask<int> Count(int count, CancellationToken token)
    {
        for (int i = 0; i < count; i++)
        {
            Debug.Log(i);
            await UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: token);
        }

        return 0;
    }

    private async void StartCount()
    {
        try
        {
            await Count(100, cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("计数取消");
        }
    }
}

17.网络请求加载图片

private async UniTaskVoid UnityTaskTest()
{
    var webRequest = UnityWebRequestTexture.GetTexture(url);
    var result = await webRequest.SendWebRequest();
    var texture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture;
    Sprite sprite = Sprite.Create(texture,
            new Rect(Vector2.zero, new Vector2(texture.width, texture.height)), new Vector2(0.5f, 0.5f));
    image2.sprite = sprite;

}

18.异步判断按钮是否被双击

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    public Button btn1;

    void Start()
    {
        CheckClickInternal(this.GetCancellationTokenOnDestroy(), 1).Forget();
    }


    /// <summary>
    /// 异步判断按钮是否被双击
    /// </summary>
    /// <param name="token"></param>
    private async UniTaskVoid CheckClickInternal(CancellationToken token, float time)
    {
        while (true)
        {
            var firstClick = btn1.OnClickAsync(token);
            await firstClick;
            var secondClick = btn1.OnClickAsync(token);

            //判断第二次点击和等待time时间谁先执行,如果是secondClick返回0,如果不是返回1
            int index = await UniTask.WhenAny(secondClick,
                UniTask.Delay(TimeSpan.FromSeconds(time), cancellationToken: token));
            if (index == 0)
            {
                Debug.Log("被双击了");
            }
        }
    }
}

19.每次点击修改按钮不同的文本

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    public Button btn1;

    // Start is called before the first frame update
    void Start()
    {
        btn1.GetComponentInChildren<Text>().text = "杀";
        ChangeBtnTextClick(this.GetCancellationTokenOnDestroy()).Forget();
    }


    /// <summary>
    /// 每次点击修改按钮不同的文本;
    /// </summary>
    /// <param name="token"></param>
    async UniTask ChangeBtnTextClick(CancellationToken token)
    {
        var click = btn1.OnClickAsAsyncEnumerable();
        await click.Take(3).ForEachAsync((_, index) =>
        {
            if (token.IsCancellationRequested) return;
            btn1.GetComponentInChildren<Text>().text = index switch
            {
                0 => "再杀",
                1 => "再补一刀",
                _ => ""
            };
        }, cancellationToken: token);
        btn1.GetComponentInChildren<Text>().text = "结束";
    }
}

四、 总结

Unitask 是一个优秀的异步任务库,它简化了在 Unity 中处理异步操作的方式,提高了开发效率和代码可维护性。通过本文的介绍,可以更加深入地了解 Unitask 的使用方法,并在自己的项目中应用它,从而提升游戏开发的质量和效率。

在使用 Unitask 时,需要注意以下几点:

​ 不要在 Update 方法中使用 async/await,因为 Unity 主线程是单线程的,使用异步方法可能导致性能问题。

​ 尽量避免过多的异步嵌套,以免导致代码复杂度过高。

​ 使用 try/catch 来处理异步操作中的错误,确保程序的稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/473278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序跨端组件库 Mpx-cube-ui 开源:助力高效业务开发与主题定制

Mpx-cube-ui 是一款基于 Mpx 小程序框架的移动端基础组件库&#xff0c;一份源码可以跨端输出所有小程序平台及 Web&#xff0c;同时具备良好的拓展能力和可定制化的能力来帮助你快速构建 Mpx 应用项目。 Mpx-cube-ui 提供了灵活配置的主题定制能力&#xff0c;在组件设计开发阶…

​HTTP与HTTPS:网络通信的安全卫士

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起进步&am…

容器中的大模型(三)| 利用大语言模型:容器化高效地部署 PDF 解析器实践...

作者&#xff1a;宋文欣&#xff0c;智领云科技联合创始人兼CTO 01 简介 大语言模型&#xff08;LLMs&#xff09;正逐渐成为人工智能领域的一颗璀璨明星&#xff0c;它们的强大之处在于能够理解和生成自然语言&#xff0c;为各种应用提供了无限可能。为了让这些模型更好地服务…

Java柠檬班Java全栈自动化课程

Java柠檬班Java全栈自动化课程旨在教授学员Java编程技能与全栈开发知识&#xff0c;包括自动化测试、前端开发和后端开发。学员将学习如何构建完整的应用程序&#xff0c;并掌握自动化测试框架&#xff0c;为职业发展打下坚实基础。 课程大小&#xff1a;14G 课程下载&#x…

PyTorch 深度学习(GPT 重译)(二)

四、使用张量表示真实世界数据 本章内容包括 将现实世界的数据表示为 PyTorch 张量 处理各种数据类型 从文件加载数据 将数据转换为张量 塑造张量&#xff0c;使其可以作为神经网络模型的输入 在上一章中&#xff0c;我们了解到张量是 PyTorch 中数据的构建块。神经网络…

挖掘网络宝藏:利用Scala和Fetch库下载Facebook网页内容

介绍 在数据驱动的世界里&#xff0c;网络爬虫技术是获取和分析网络信息的重要工具。本文将探讨如何使用Scala语言和Fetch库来下载Facebook网页内容。我们还将讨论如何通过代理IP技术绕过网络限制&#xff0c;以爬虫代理服务为例。 技术分析 Scala是一种多范式编程语言&…

【云原生 • Kubernetes】认识 k8s、k8s 架构、核心实战

文章目录 Kubernetes基础概念1. 是什么2. 架构2.1 工作方式2.2 组件架构 3. k8s组件创建集群步骤一 基础环境步骤二 安装kubelet、kubeadm、kubectl步骤三 主节点使用kubeadm引导集群步骤四 副节点加入主节点步骤五 部署dashboard Kubernetes核心实战1. 资源创建方式2. Namespa…

stable diffusion webui ubuntu 安装

1.git clone 下来 GitHub - AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UIStable Diffusion web UI. Contribute to AUTOMATIC1111/stable-diffusion-webui development by creating an account on GitHub.https://github.com/AUTOMATIC1111/stable-diffus…

python爬虫基础实验:通过DBLP数据库获取数据挖掘顶会KDD在2023年的论文收录和相关作者信息

Task1 读取网站主页整个页面的 html 内容并解码为文本串&#xff08;可使用urllib.request的相应方法&#xff09;&#xff0c;将其以UTF-8编码格式写入page.txt文件。 Code1 import urllib.requestwith urllib.request.urlopen(https://dblp.dagstuhl.de/db/conf/kdd/kdd202…

钡铼技术R40工业4G路由器加速推进农田水利设施智能化

钡铼技术R40工业4G路由器作为一种先进的通信设备&#xff0c;正在被广泛应用于各行各业&#xff0c;其中包括农田水利设施的智能化改造。通过结合钡铼技术R40工业4G路由器&#xff0c;农田水利设施可以实现更高效的管理和运营&#xff0c;提升农田灌溉、排水等工作效率&#xf…

Idea 不能创建JDK1.8的spring boot项目

由于https://start.springboot.io/ 不支持JDK1.8&#xff0c;那么我们需要换idea的springboot创建源&#xff0c;需要换成 https://start.aliyun.com&#xff0c;这也是网上大部分教程说的&#xff0c;但是我这边会报这样的错误&#xff1a; Initialization failed for https:…

流畅的 Python 第二版(GPT 重译)(九)

第四部分&#xff1a;控制流 第十七章&#xff1a;迭代器、生成器和经典协程 当我在我的程序中看到模式时&#xff0c;我认为这是一个麻烦的迹象。程序的形状应该只反映它需要解决的问题。代码中的任何其他规律性对我来说都是一个迹象&#xff0c;至少对我来说&#xff0c;这表…

自动化的免下车服务——银行、餐厅、快餐店、杂货店

如果您在20世纪70年代和2020年分别驾车经过免下车服务餐厅&#xff08;汽车穿梭餐厅&#xff09;&#xff0c;您会发现&#xff0c;唯一的不同是排队的车型。50多年来&#xff0c;免下车技术一直为我们提供着良好的服务&#xff0c;但现在也该对它进行现代化改造了。 乘着AI和自…

QGIS编译(跨平台编译)056:PDAL编译(Windows、Linux、MacOS环境下编译)

点击查看专栏目录 文章目录 1、PDAL介绍2、PDAL下载3、Windows下编译4、linux下编译5、MacOS下编译1、PDAL介绍 PDAL(Point Data Abstraction Library)是一个开源的地理空间数据处理库,它专注于点云数据的获取、处理和分析。PDAL 提供了丰富的工具和库,用于处理激光扫描仪、…

SecureCRT:高效安全的远程连接工具

SecureCRT是一款功能强大的终端仿真工具&#xff0c;主要用于连接和运行包括Windows、UNIX和VMS在内的远程系统。它支持多种协议&#xff0c;如SSH1、SSH2、Telnet、SFTP、Rlogin、Serial、SCP等&#xff0c;确保用户与目标设备之间的通信安全&#xff0c;并防止网络攻击和窥探…

Crypto Gladiator League (CGL)

《加密角斗士》是一款完全链上游戏。所有角斗士、装备、代币等的生成过程都可以透明追溯。不可能被篡改或欺骗&#xff0c;使所有游戏物品都是真实资产。 CGL 现已升级为全链游戏平台和 Web3 游戏流量门户&#xff0c;通过多维度收集用户数据&#xff0c;并将数据应用于游戏中&…

ChatGPT在大气科学领域建模、数据分析、可视化与资源评估中的高效应用及论文写作

深度探讨人工智能在大气科学中的应用&#xff0c;特别是如何结合最新AI模型与Python技术处理和分析气候数据。课程介绍包括GPT-4等先进AI工具&#xff0c;旨在帮助学员掌握这些工具的功能及应用范围。课程内容覆盖使用GPT处理数据、生成论文摘要、文献综述、技术方法分析等实战…

Kafka生产者相关概念

文章目录 Kafka工作流程Kafka文件存储生产者分区策略生产者ISR生产者ack机制数据一致性问题ExactlyOnce Kafka工作流程 Kafka中消息是以topic进行分类的&#xff0c;Producer生产消息&#xff0c;Consumer消费消息&#xff0c;都是面向topic的。 Topic是逻辑上的概念&#xff…

python日常刷题(一)

前言&#xff1a;本文记录2024年3月11日至2024年3月19日牛客网所做的基础题目&#xff08;错题本&#xff09;&#xff1a; &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;本专栏&#xff1a;python日常刷题 &#x1f380;CSDN主页&#xff1a;愚润求学 文章目录…

音频转换器哪个好?5个角度详细测评~

我们常常会用到音频转换器&#xff0c;比如因为平台和设备对某些格式的不兼容&#xff0c;需要进行格式转换&#xff1b;比如有些音频文件可能过大&#xff0c;需要转换为更高效&#xff1b;压缩格式以节省存储空间或加快传输速度&#xff1b;比如调整音频文件的比特率、采样率…
最新文章