ue3dUnity中的异步如何使用?

Unity中的异步如何使用?

分类:
ue3d - Unity中的异步如何使用?

Async/Await是Unity中的C#脚本功能,允许异步执行部分功能,异步函数通过等待其他事情来工作,允许中途暂停它们,直到完成特定任务。

这类似于协程在帧之间的拆分方式,函数的执行在某个点暂停,当它恢复时,从它停止的地方开始。

然而,不同之处在于,虽然协程通常有意地随着时间的推移执行逻辑,使用yield语句将函数分成多个阶段,但异步函数可用于等待另一个操作完成后再做其他事情。

这意味着将能够在后台运行昂贵的操作,而无需在此过程中停止游戏。

运作的原理

要创建异步函数,需要在方法的返回类型之前添加async关键字。

async void DoSomething()
{
    // Do something!
}

但是,仅此一项还不足以创建异步函数。

为了异步运行函数的一部分,需要等待任务完成,使用await关键字和Task类型。

例如:

async void DoSomething()
{
    Debug.Log("Wait for 3 seconds");
    await Task.Delay(3000);
    Debug.Log("3 seconds later");
}

任务是异步操作的表示。

它可能是一个延迟,如上例所示,或者是一个返回任务类型的方法,允许异步方法等待它。

而且,当它这样做时,它会停止正在做的事情,只有在等待的任务完成后才会继续。

这是将异步运行的异步函数的唯一部分,这意味着必须包含一个可等待的任务才能完全使用异步。

ue3d - Unity中的异步如何使用?

即使是异步函数也会被同步处理,就像其他一切一样。也就是说,直到等待一个任务,然后该任务将在后台发生。

可等待任务之前或之后的任何代码都将同步发生,阻塞主线程,就像其他任何事情一样。

这意味着,为了使用async,必须使用await,并且为了使用await ,必须有一个任务供其等待。

如何在Unity中创建任务

在可以创建任何类型的任务之前,需要将System Threading Tasks命名空间添加到脚本的顶部。

例如:

using UnityEngine;
using System.Threading.Tasks;

完成后,将能够使用和创建Tasks。

任务类代表一种异步操作。

重要的是,它的进度是可跟踪的,这允许异步函数等待任务完成,而无需停止进程中的其他所有内容。

可以用任务做什么?

一种选择是通过让出它来暂停当前函数的执行,就像在协程中使用Yield语句一样。

例如,While循环会继续执行,直到其条件不再为真。

例如:

void CountToTen()
{
    int number = 0;
    while (number < 10)
    {
        number++;
        Debug.Log(number);
    }
    Debug.Log("I've finished counting!");
}

在常规函数中,这意味着它在同一帧中同时发生。

但是,这很容易引起问题,因为除非其内容允许它跳出自己的循环,否则在常规函数中运行while循环会导致Unity冻结。

发生这种情况是因为Unity同步处理while循环,这意味着它无法执行任何其他操作,直到循环的条件不再为真。

但是,使用Task产生循环可以暂停函数的执行,从而允许它在多个帧上进行处理,而不仅仅是一个帧。

例如:

async void CountToTenAsync()
{
    int number = 0;
    while (number < 10)
    {
        number++;
        Debug.Log(number);
        await Task.Yield();
    }
    Debug.Log("I've finished counting!");
}

这意味着,即使你的while循环包含一个无限真实的条件,因为它是使用任务产生的,它只是意味着它会在每一帧发生,而不是永远在一帧中发生。

但是,如果不想等到下一帧怎么办?如果想等待一段时间怎么办?

就像协程一样,可以将函数暂停一段特定的时间,之后函数将通过等待延迟任务从中断的地方继续。

例如:

async void Wait()
{
    Debug.Log("Give me a second...");
    await Task.Delay(1000);
    Debug.Log("Ok, I'm done.");
}

与协程中的Wait For Seconds不同, Task Delay接受以毫秒为单位的持续时间,而不是秒。

这意味着,如果想将秒数传递给延迟参数,则需要将持续时间乘以1000。

例如:

async void Wait() 
{ 
    // Waits 2.5 seconds
    await Task.Delay((int)2.5 * 1000); 
}

虽然为下一帧让步,或者在做其他事情之前等待一定时间过去,这两种方法都很有用,但它们通常可以使用协程解决的问题。

这意味着,除了工作流程的差异之外,对于这些类型的任务,使用异步而不是协程并没有真正的好处。

相反,为了充分利用异步,可能会发现等待实际函数完成更有用。

那如何做呢?

等待函数在后台完成的一种方法是等待返回Task类型的异步函数。

例如:

async void Start()
{
    await MyFunction();
    Debug.Log("All Done!");
}
async Task MyFunction()
{
    // Waits 5 seconds
    await Task.Delay(5000);
}

但是…

为了使其工作,等待的任务本身必须等待其他任务。其中,如果正在做一些返回任务类型的事情,例如将某事延迟一段时间,这不是问题。

但是…

如果只想执行一段可能需要一段时间才能处理的代码,但实际上并没有等待任何东西,那么如果想异步处理它,则需要将其传递给Task将方法作为匿名函数运行。

例如:

async void Start()
{
    await Task.Run(() => Count());
    Debug.Log("All Done!");
}
void Count()
{
    for (int i = 0; i < 10000; i++)
    {
        Debug.Log(i);
    }
}

这通常允许同步代码块在后台运行。

何时使用异步或等待?

Unity中异步任务的主要好处是,与常规函数不同,它们不会阻塞主线程。这意味着可以使用async故意在后台执行昂贵的操作,这样它就不会在游戏运行时完全停止游戏,从而改善玩家的整体体验。

例如:

Unity的一些内置功能,如加载场景,或导入大型资产,如音频数据,正是出于这个原因,已经提供了异步替代方案。

作为异步如何有用的示例,它们是后台操作的良好候选者,因为它们通常需要很长时间才能完成,但在处理它们时停止游戏是不合适的。

虽然async/await工作流,如果项目中有类似的任务,可能需要一段时间才能运行,但并不一定需要在游戏停止时停止,它允许执行相同的操作。

但是,为什么要停在那里?

如果async/await工作流更容易使用,而且通常不会阻塞主线程,为什么不使用它来完全取代协程呢?

该问题可以参阅站内文章:Unity中的异步与协程

….

以上是在Unity中关于异步如何使用的全部内容,如果你有任何反馈,请随时在本页面下方留言。

相关信息

  • 类型:教程
  • 字数:1620
  • 字符:4790
  • 适用软件:Unity
  • 说明:无
  • 编号:109962

热门内容

提示:3D天堂作为服务提供者,尊重网络版权及知识产权,对某些行为的发生不具备充分的监控能力,若无意间侵犯到您的权利,请 联系我们,我们会在收到信息后尽快给予处理。

本站文章版权归本站自创作者所有,未经允许不得转载!