在Unity游戏循环中优雅地使用任务

huangapple go评论71阅读模式
英文:

Elegant use of Tasks on the Unity game loop

问题

在我的Unity组件中,我需要使用Task来进行工作。在FixedUpdate中,我需要调用一个异步方法,该方法会立即返回一个Task。每当Task完成时,我也需要在(未来的)FixedUpdate中处理结果(然后重复这个过程)。

所以我的代码大致如下:

void FixedUpdate() {
  if (_task == null) {
    _task = CallAsyncMethod();
  } else if (_task.isCompleted) {
    var result = _task.Result;
    ApplyResult(result);
    _task = null;
  }
}

这感觉像是对Task的尴尬使用,因为我需要在游戏循环中处理结果,但我无法想到任何根本上的问题。

问题:

  • 我的实现是正确的而且不浪费吗?
  • 是否有更优雅的方法来满足相同的约束?(即在FixedUpdate中启动一个Task并处理其结果)
英文:

I need to work with Tasks in my Unity component. In FixedUpdate, I need to call an async method, which returns right away, giving me a Task. Whenever the Task completes, I also need to handle the result in (a future) FixedUpdate (and then repeat the process).

So my code looks roughly like this:

void FixedUpdate() {
  if (_task == null) {
    _task = CallAsyncMethod();
  } else if (_task.isCompleted) {
    var result = _task.Result;
    ApplyResult(result);
    _task = null;
  }
}

This feels like an awkward use of Task due to the fact that I need to handle the result on the game loop, but I can't think of anything fundamentally wrong with it.

Questions:

  • Is my implementation correct and not wasteful?
  • Is there a more elegant way to satisfy the same constraints? (i.e. both start a Task and handle its result in FixedUpdate)

答案1

得分: 2

在我的经验中,尝试在Unity的更新循环中使用异步模式是一项无休止的令人沮丧的练习,因为它倾向于产生许多边缘情况。

您最好尽量避免使用异步,而是使用协程。

如果您绝对必须使用异步函数,考虑在游戏开始时创建自己的独立线程来管理和调用它们。但随后您必须找出线程安全的方法来将数据交换回主游戏线程。

英文:

In my experience, trying to use async patterns with Unity's update loop is an endless exercise in frustration, as it tends to spawn many edge cases.

Your best bet is to avoid async at all costs and use Coroutines instead.

If you absolutely must use async functions, consider spawning your own separate thread at the beginning of the game to manage and invoke them. But then you have to figure out thread-safe ways to exchange data back to the main game thread.

答案2

得分: 0

以下是代码部分的翻译:

你至少可以跳过`null`检查,直接在第一个任务完成后开始新的任务。这样看起来会更不“丑陋”,并且可以去掉一个`FixedUpdate`间隔的延迟;

void Start()
{
    _task = CallAsyncMethod();
}

void FixedUpdate()
{
    if (!_task.isCompleted) return;

    var result = _task.Result;
    ApplyResult(result);
    _task = CallAsyncMethod();
}

或者使用Coroutine,例如:

private IEnumerator Start()
{
    while (true)
    {
        var task = CallAsyncMethod();
        yield return new WaitUntil(() => task.isCompleted);
        yield return new WaitForFixedUpdate();
        var result = _task.Result;
        ApplyResult(result);
    }
}

但是,如果你真的想充分利用Unity中的异步操作,你应该查看UniTask并进行如下操作:

void Start()
{
    ApplyContinously().Forget();
}

private async UniTaskVoid ApplyContinously()
{
    while (true)
    {
        var result = await CallAsyncMethod();

        await UniTask.WaitForFixedUpdate();

        ApplyResult(result);
    }
}

请注意,上述内容仅为代码的翻译,不包含问题的回答。

英文:

You could at least skip the null check and rather directly start a new task after the first one finished. That would make it look less "ugly" and also remove the delay of one FixedUpdate interval 在Unity游戏循环中优雅地使用任务

void Start()
{ 
    _task = CallAsyncMethod(); 
} 

void FixedUpdate() 
{ 
    if (!_task.isCompleted) return;

    var result = _task.Result;
    ApplyResult(result); 
    _task = CallAsyncMethod(); 
}

Or use a Coroutine like e.g.

private IEnumerator Start ()
{
    while(true)
    {
       var task = CallAsyncMethod();
       yield return new WaitUntil(() => task.isCompleted);  
       yield return new WaitForFixedUpdate();
       var result = _task.Result;
       ApplyResult(result);  
    }
}

But if you really want to do async stuff in Unity in its full potential you should check out UniTask and do e.g.

void Start()
{
    ApplyContinously().Forget();
}

private async UniTaskVoid ApplyContinously()
{
    while(true)
    {
        var result = await CallAsyncMethod();

        await UniTask.WaitForFixedUpdate();

        ApplyResult(result);
    }
}

huangapple
  • 本文由 发表于 2023年2月14日 05:38:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75441433.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定