【问题标题】:In Unity, does different "yield return X" Coroutine always run in order?在 Unity 中,不同的“yield return X”协程是否总是按顺序运行?
【发布时间】:2021-11-27 11:03:36
【问题描述】:

【代码】

private void Start()
{
    StartCoroutine(A1());
    StartCoroutine(A2());
    StartCoroutine(A3());
}

IEnumerator A1()
{
    while (true)
    {
        print("A1");
        yield return new WaitForSeconds(3);
    }
}
IEnumerator A2()
{
    while (true)
    {
        print("A2");
        yield return new WaitForSeconds(3);
    }
}
IEnumerator A3()
{
    while (true)
    {
        print("A3");
        yield return new WaitForSeconds(3);
    }
}

【输出】

A1
A2
A3
A1
A2
A3
A1
A2
A3
A1
A2
A3
...

【我的问题】

A1(),A2(),A3() 总是按顺序运行。

确定吗?
“yield return null”、“yield return WaitForSeconds”和其他“yield return X”是一样的吗?

为什么我有这个问题?
在 Unity 的Order of execution for event functions 中,不同的“收益回报 X”发生在不同的时间。
然后我想知道,如果几个相同类型的“yield return X”(在同一个 MonoBehaviour 中)总是按顺序发生。

更新1

1.1

@joreldraw 在评论中说

将 A1 更改为 20 秒,将 A2 更改为 10,然后重试 :)

这是代码和输出。

【代码】

private void Start()
{
    StartCoroutine(A1());
    StartCoroutine(A2());
}

IEnumerator A1()
{
    while (true)
    {

        print($"A1,frame:{Time.frameCount},time:{Time.time}");
        yield return new WaitForSeconds(10f);
    }   
}
IEnumerator A2()
{
    while (true)
    {

        print($"A2,frame:{Time.frameCount},time:{Time.time}");
        yield return new WaitForSeconds(20f);
    }
}

【输出】

A1,帧:3187,时间:10.00139
A2,帧数:6495,时间:20.0001
A1,帧:6496,时间:20.00392
A1,帧:9686,时间:30.00965
A2,帧:13093,时间:40.0004
A1,帧:13095,时间:40.01266
A1,帧:16445,时间:50.01303
A2,帧数:19695,时间:60.00157
A1,帧:19699,时间:60.01489

1.2

我想知道的是,它们在同一帧时是否保持有序。
所以我把时间改成 0.01s 和 0.02s 。

【输出】

A1,帧:3,时间:0.3533334
A2,帧:3,时间:0.3533334
...
A2,帧:10,时间:0.4100522
A1,帧:11,时间:0.4132612
A1,帧:15,时间:0.4247341
...
A1,帧:38,时间:0.4942196
A2,帧:38,时间:0.4942196
...
A2,帧数:52,时间:0.5754243
A1,帧:52,时间:0.5754243
A1,帧:54,时间:0.5914614
...

1.3

很难确定协程是否保持有序。所以我修改了代码,只在协程在同一帧运行时才打印。

HashSet<int> a1Set = new HashSet<int>();
HashSet<int> a2Set = new HashSet<int>();
private void Start()
{
    StartCoroutine(A1());
    StartCoroutine(A2());
}

IEnumerator A1()
{
    while (true)
    {
        a1Set.Add(Time.frameCount);
        if (a2Set.Contains(Time.frameCount))
        {
            print($"First 2, Then 1, frame:{Time.frameCount}");
        }
        yield return new WaitForSeconds(0.01f);
    }   
}
IEnumerator A2()
{
    while (true)
    {
        a2Set.Add(Time.frameCount);
        if (a1Set.Contains(Time.frameCount))
        {
            print($"First 1, Then 2, frame:{Time.frameCount}");
        }
        yield return new WaitForSeconds(0.02f);
    }
}

【输出】

前 1,后 2,帧:3
先1,后2,帧:4
先2,后1,帧:9
先2,后1,帧:16
先2,后1,帧:22
先2,后1,帧:28
先1,后2,帧:76
先1,后2,帧:135
先1,后2,帧:179
先2,后1,帧:186
先1,后2,帧:222

【问题讨论】:

  • 将您的 A1 更改为 20 秒,A2 更改为 10,然后再试一次 :)
  • @joreldraw 为什么?我不认为这是这里的问题^^
  • 您的实际用例是什么?为什么不简单地使用一个每 3 秒按顺序执行 A0-4 的例程?
  • @derHugo 这里没有用例。我想到了这个问题^^(所以这可能是一个毫无意义的问题)。我知道 Unity 的“事件执行顺序”,不同类型的“收益回报 X”发生在不同的时间。然后我想知道,如果几个相同类型的“yield return X”(在同一个 MonoBehaviour 中)按顺序发生。
  • @joreldraw 我根据你的评论做了一些测试。他们已被添加到帖子中。

标签: unity3d coroutine


【解决方案1】:

在您描述的情况下是的!顺序始终相同,因为您一个接一个地启动它们,它们都等待 3 秒,所以第一个总是领先。 yield return null 也是一样,因为它会在下一帧中执行。当您从不同的 Update()/Start() 方法启动 couroutines 时会变得很棘手,因为不能保证这些方法的执行顺序。如果您需要它们以特定顺序执行,请尝试不同的等待间隔或使用此处描述的其他统一函数:https://docs.unity3d.com/Manual/ExecutionOrder.html?_ga=2.194867501.1256475209.1612055407-571780476.1550264998#Coroutines

【讨论】:

  • 谢谢。我知道“事件的执行顺序”。它说不同类型的收益率回报发生在不同的时间。但它并没有说明相同的收益率回报是否按顺序发生。所以我问了这个问题。
  • 我认为这个问题(stackoverflow.com/questions/12932306/…)可能对我有帮助。有点长,还没看。
  • 相同的收益回报按开始的顺序发生。例如,如果您有 2 个带有 yield return WaitForSeconds(2) 的协程都在 2 秒后继续,但是您首先启动的协程更早执行,因为它开始更早地等待,因为它是首先执行的
  • 添加了更多测试。在 Update1 - 1.3 中,“yield return new WaitForSeconds(0.01f);” vs“收益返回新的WaitForSeconds(0.02f);”不会按顺序发生。如果您有兴趣,请查看它。
  • 是的,因为等待时间不同
【解决方案2】:

协程的开始按照你的代码顺序:

private void Start()
{
    StartCoroutine(A1()); //Firt
    StartCoroutine(A2()); //Second
}

协程的结果取决于你为等待添加的执行时间:

IEnumerator A1()
{
    Debug.Log("Started Coroutine A1 at : " + Time.time);
     yield return new WaitForSeconds(0.01f);

     //Here your code for the result after waitforsecond
     Debug.Log("Finished Coroutine A1 at : " + Time.time);   
}
IEnumerator A2()
{
     Debug.Log("Started Coroutine at A2 : " + Time.time);
     yield return new WaitForSeconds(0.02f);

     //Here your code for the result after waitforsecond
     Debug.Log("Finished Coroutine A2 at : " + Time.time);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 2017-01-02
    • 2019-04-03
    • 1970-01-01
    • 2018-12-18
    • 2019-01-04
    • 2021-08-03
    相关资源
    最近更新 更多