Unity C# 之 Task、async和 await 结合使用的一些情况处理

Unity C# 之 Task、async和 await 结合使用的一些情况处理

目录

[Unity C# 之 Task、async和 await 结合使用的一些情况处理](# 之 Task、async和 await 结合使用的一些情况处理)

一、简单介绍

[二、把 async 函数,通过变化转为一般的函数](#二、把 async 函数,通过变化转为一般的函数)

[三、在 async 函数中,切换到主线程,并等待主线程执行完毕,继续 async 中的代码](#三、在 async 函数中,切换到主线程,并等待主线程执行完毕,继续 async 中的代码)


一、简单介绍

Unity 在使用 Task 结合 async (await) 的时候,偶尔会遇到一些特殊情况,需要进行一些简单变化的处理,在这里自己做一个简单的记录,以便后期使用的时候参考。

Task 看起来像一个Thread,实际上,它是在ThreadPool的基础上进行的封装,Task的控制和扩展性很强,在线程的延续、阻塞、取消、超时等方面远胜于Thread和ThreadPool。

async 和 await ,await 运算符暂停对其所属的 async 方法的求值,直到其操作数表示的异步操作完成。 异步操作完成后,await 运算符将返回操作的结果(如果有)。 当 await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停其所属的方法。 await 运算符不会阻止计算异步方法的线程。 当 await 运算符暂停其所属的异步方法时,控件将返回到方法的调用方。

在方法里加上了 async 关键字后,注意:返回值就只能使用固定的几个了,不然会报错

  1. 异步函数的返回类型只能为: void、Task、Task<TResult>、ValueTask 或 ValueTask<TResult>
  2. Task<TResult>: 代表一个返回值T类型的操作。
  3. Task: 代表一个无返回值的操作。
  4. void: 为了和传统的事件处理程序兼容而设计。

二、把 async 函数,通过变化转为一般的函数

情况是这样的,在一个开发需求中

  • 1)需要把一些函数定义在一个字典Dictionary 中,字典形式是Dictionary<string,func<string,string>>
  • 2)在添加函数时,有一个接口是 async Task<string> MethodAsync(string) 形式的,不能正常添加到字典中

此时,就需要把之前的 async Task<string> MethodAsync(string) 函数进行二次封装,变为可以赋值到字典中的函数形式,就是通过获取到 async Task<string> MethodAsync(string) 函数的 Task<string> 获取 Task 任务,执行 Task.wait() 等待,获取 Task.Result() 结果即可,参考代码如下,最后把 Method 的方法添加到字典中即可

cs 复制代码
//之前的函数形式
async Task<string> MethodAsync(string);

// 重新封装为可以正常调用的函数形式
string Method(string){

        // 将异步任务等待并获取结果
        Task<string> task = MethodAsync(string);
        task.Wait(); // 或者使用 task.Result

        return task.Result;
}

三、在 async 函数中,切换到主线程,并等待主线程执行完毕,继续 async 中的代码

情况是这样的,在 Unity 开发中,需要async 开发来避免阻塞主线程,分担主线程的压力,但是在Unity 中有些函数必须在主线程执行,如果在 async 线程中执行你会得不到想要的结果。

处理方式如下:

1) 在 async 函数中,把需要的在主线程执行的代码切换的主线程,使用Loom.QueueOnMainThread(()=>{需要在主线程执行的代码;})(这里使用 Loom 封装,进行主子线程切换,大家网上搜索 C# Loom即可找到该函数的封装)

2)如果只是上面操作,可能主子线程各自执行,子线程不会等待主线程完成

3)如果需要子线程等待主线程执行完毕之后,才执行子线程的代码,可以创建一个 TaskCompletionSource<bool> ,在子线程中等待 await TaskCompletionSource.Task 该 任务完成标志,所以这是 主线程执行完后TaskCompletionSource 设置为 true 即可,即是 TaskCompletionSource.SetResult(true) ,参考代码如下

cs 复制代码
private async Task<string> MethodAsync() {

        // 创建一个 TaskCompletionSource
        var tcs = new TaskCompletionSource<bool>();
        string reslt= "";

        Loom.QueueOnMainThread(() => {
                // 主线程处理代码过程
                ......

                reslt=  "处理获取结构";

                // 完成 TaskCompletionSource,使得任务线程继续执行
                tcs.SetResult(true);
            });

            // 切换到主线程执行一段代码
            await tcs.Task;

        return reslt;
        
    } 


private async Task<string> MethodAsync() {

        // 创建一个 TaskCompletionSource
        var tcs = new TaskCompletionSource<bool>();
        string reslt= "";
        await System.Threading.Tasks.Task.Run(async () => {

            Loom.QueueOnMainThread(() => {
                // 主线程处理代码过程
                ......

                reslt=  "处理获取结构";

                // 完成 TaskCompletionSource,使得任务线程继续执行
                tcs.SetResult(true);
            });

            // 切换到主线程执行一段代码
            await tcs.Task;

        });

        return reslt;
        
    }
相关推荐
异次元的归来2 小时前
Unity DOTS中的share component
unity·游戏引擎
向宇it5 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
_oP_i6 小时前
unity webgl部署到iis报错
unity
Go_Accepted6 小时前
Unity全局雾效
unity
向宇it6 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
每日出拳老爷子9 小时前
【图形渲染】【Unity Shader】【Nvidia CG】有用的参考资料链接
unity·游戏引擎·图形渲染
北海651610 小时前
Dots 常用操作
unity
坐井观老天11 小时前
在C#中使用资源保存图像和文本和其他数据并在运行时加载
开发语言·c#
pchmi13 小时前
C# OpenCV机器视觉:模板匹配
opencv·c#·机器视觉
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭15 小时前
C#都可以找哪些工作?
开发语言·c#