unity的异步操作

1.C#提供了两个关键字来实现异步async和await

async 关键字用于声明一个异步方法。该方法内部可以使用 await 关键字来等待异步操作的完成。当方法被标记为 async 时,它隐式地表示该方法可能会包含一个或多个 await 表达式。重要的是要注意,async 方法通常会返回一个 Task 或 Task<T> 类型的对象,其中 T 是方法的返回类型。

await 关键字用于等待一个异步操作的完成。它只能在被 async 修饰的方法内部使用。当遇到 await 表达式时,编译器会自动将方法分成两部分:await 表达式之前的代码会在原始线程上同步执行,而 await 表达式之后的代码会在异步操作完成时,在另一个线程(或从线程池中获取的线程)上继续执行。这个过程是自动的,不需要开发者手动管理线程。

例子:

using System;  
using System.IO;  
using System.Threading.Tasks;  
  
class Program  
{  
    static async Task Main(string[] args)  
    {  
        string content = await ReadFileAsync("example.txt");  
        Console.WriteLine(content);  
    }  
  
    static async Task<string> ReadFileAsync(string filePath)  
    {  
        using (StreamReader reader = new StreamReader(filePath))  
        {  
            // 注意:StreamReader 没有直接的异步读取方法,这里为了示例  
            // 我们假设有一个,但在现实中,你可能会使用 File.ReadAllTextAsync 等  
            // 这里使用 Task.Run 来模拟异步操作  
            string content = await Task.Run(() =>  
            {  
                return reader.ReadToEnd();  
            });  
            return content;  
        }  
    }  
}  
  
// 注意:上面的 ReadFileAsync 方法中使用了 Task.Run 来模拟异步操作,  
// 但在实际应用中,读取文件应该使用 File.ReadAllTextAsync 或类似的异步API。

2.UniTask

Task的升级版本(第三方弄出来代替Task和协程的方案),0GC的真异步解决方案。

例子:

public async UniTask AsyncSetImage(string address)
{
    ZCancelSource.Return(ref cancelSource_);
    cancelSource_ = ZCancelSource.Rent();
    try
    {
        Sprite spr = await ZResLoader.Instance.LoadAssetAsync<Sprite>(address, cancelSource_.CreateToken(), 1000);
        this.sprite = spr;

        ZCancelSource.Return(ref cancelSource_);
    }
}

 3.打断操作

unitask提供了CancelTokenSource,但会有GC,所以最好还是自己写一套

ZCancelSource:管理一组CancelToken(uint类型,每次照上一次递增,在0-uint.maxvalue中循环,维护一个dict来标记token是否存在),每个CancelToken对应一个异步逻辑,可以指定打断/取消某一个异步逻辑。

private static async UniTask<object> loadAssetAsyncInternal(uint realAddress, uint token)
{
...
    if (ZCancelSource.IsCanceled(token))
    {
        throw new ArgumentException($"[ZResLoader] invaid token on LoadAssetAsync, token={token}");
    }
...

     while (!asset.IsDone && !ZCancelSource.IsCanceled(token))
    {
        await UniTask.Yield();
    }

    if (ZCancelSource.IsCanceled(token))
    {
        asset.Release();
        throw ZCancelSource.CancelException;
    }

    ZCancelSource.ReleaseToken(token);
...
}

 

posted @ 2024-09-02 21:06  mc宇少  阅读(134)  评论(0编辑  收藏  举报