
虽然Unity简单地放弃或延迟异步任务可能比使用协程简单得多,但取消它可能会稍微复杂一些。
这是因为,为了取消异步函数,或者至少取消函数中实际异步的部分,即Task ,需要一个Cancellation Token。
这是通过声明Cancellation Token Source来实现的,它可用于在任务运行时向其提供取消令牌。
然后,如果对象被销毁,它可以使用取消令牌源也取消其令牌传递到的任务。
例如:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using System.Threading;
public class AsyncExample : MonoBehaviour
{
CancellationTokenSource cancellationTokenSource;
void Start()
{
StartCoroutine(MyTask());
MyTaskAsync();
Destroy(gameObject);
}
private void OnDestroy()
{
cancellationTokenSource?.Cancel();
}
async void MyTaskAsync()
{
cancellationTokenSource = new CancellationTokenSource();
Debug.Log("Async Task Started on: " + gameObject);
await Task.Delay(5000, cancellationTokenSource.Token);
Debug.Log("Async Task Ended on: " + gameObject);
}
IEnumerator MyTask()
{
Debug.Log("Task Started");
yield return new WaitForSeconds(5);
Debug.Log("Task Ended on: " + gameObject);
}
}
然而,虽然这将取消任务,但它也会在执行时导致任务取消异常。

要解决此问题,需要使用Try/Catch语句,try/Catch语句的工作方式与if/else语句类似,只是它处理异常错误,而不是条件。
该函数将尝试处理Try块,如果抛出异常,则根据异常类型处理Catch块,这允许任务在捕获到异常时从函数中返回,而不是尝试继续。
例如:
async void MyTaskAsync()
{
cancellationTokenSource = new CancellationTokenSource();
Debug.Log("Async Task Started on: " + gameObject);
try
{
await Task.Delay(5000, cancellationTokenSource.Token);
}
catch
{
Debug.Log("Task was cancelled!");
return;
}
finally
{
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
Debug.Log("Async Task Ended on: " + gameObject);
}

最后,Finally Block总是被处理,无论是在任务成功运行之后还是失败之后,并且对于函数之后的清理很有用。
在这种情况下,通过处理Cancellation Token Source,这对于避免内存泄漏很重要。虽然这些都不是特别困难,但它确实使异步函数的使用比最初看起来要复杂一些。
那使用协程还是异步/等待呢?
一般来说,因为它们以不同的方式工作,所以在协程和异步或等待之间进行选择并不总是像选择喜欢的框架那么简单。
例如:
协程更适合不需要仔细管理的即发即弃任务。在后台处理密集型任务时,它不会在游戏运行时停止运行,只能使用异步来真正完成。
协同程序有时使用起来很麻烦,但是异步函数虽然一开始看起来很简单,但一旦需要取消正在运行的任务,就会变得复杂得多。
但是…
实际上,有时可能需要在项目中同时使用这两种方法。
在这种情况下,一般情况下更容易将协程用于对象相关的游戏逻辑,并在最有意义的时候保存异步。
例如在后台执行长时间运行的任务时。
…
以上是关于如何取消Unity异步功能的全部内容,如果你有任何反馈,请随时在本页面下方留言。