C# 调用并行协同程序并等待它们全部结束

C# 调用并行协同程序并等待它们全部结束,c#,unity3d,coroutine,ienumerator,C#,Unity3d,Coroutine,Ienumerator,我有一些共同计划: IEnumerator a(){ /* code */ } IEnumerator b(){ /* code */ } IEnumerator c(){ /* code */ } 我想创建一个并行调用a、b和c的协同程序,但要等待它们全部完成后才能继续,例如: IEnumerator d(){ StartCoroutine(a()); StartCoroutine(b()); StartCoroutine(c()); wait until a

我有一些共同计划:

IEnumerator a(){ /* code */ }
IEnumerator b(){ /* code */ }
IEnumerator c(){ /* code */ }
我想创建一个并行调用
a
b
c
的协同程序,但要等待它们全部完成后才能继续,例如:

IEnumerator d(){
    StartCoroutine(a());
    StartCoroutine(b());
    StartCoroutine(c());
    wait until all of them are over
    print("all over");
}
显然,我可以为每个协同路由使用一个布尔值来保存其当前状态,但由于这种方法不可扩展,我更喜欢一种更直接的解决方案。

安装这种方法时,可以将其实现为异步协同路由混合方法:

using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class TestCoroutines : MonoBehaviour
{

    void Start () => D();

    IEnumerator A () { yield return new WaitForSeconds(1f); print($"A completed in {Time.time}s"); }
    IEnumerator B () { yield return new WaitForSeconds(2f); print($"B completed in {Time.time}s"); }
    IEnumerator C () { yield return new WaitForSeconds(3f); print($"C completed in {Time.time}s"); }

    async void D ()
    {
        Task a = Task.Run( async ()=> await A() );
        Task b = Task.Run( async ()=> await B() );
        Task c = Task.Run( async ()=> await C() );

        await Task.WhenAll( a , b , c );

        print($"D completed in {Time.time}s");
    }

}
控制台输出:

A completed in 1.006965s
B completed in 2.024616s
C completed in 3.003201s
D completed in 3.003201s
您可以尝试调用(“MethodName”,timeinFloat)并在每个方法中添加一个计数器(int)/bool。当所有这些都运行完后,根据计数器/bool条件,您可以继续执行


如果调用时间设置为0,它将在下一个更新帧周期中运行,这是我使用的方法,它也是一个有点清晰的代码,易于使用:

IEnumerator First() { yield return new WaitForSeconds(1f); }
IEnumerator Second() { yield return new WaitForSeconds(2f); }
IEnumerator Third() { yield return new WaitForSeconds(3f); }

IEnumerator d()
{
    Coroutine a = StartCoroutine(First());
    Coroutine b = StartCoroutine(Second());
    Coroutine c = StartCoroutine(Third());

    //wait until all of them are over
    yield return a;
    yield return b;
    yield return c;

    print("all over");
}

您还可以使用协同例程后面的底层迭代器,自己调用
MoveNext

在您的示例中,它将类似于

IEnumerator a(){/*code*/}
IEnumerator b(){/*代码*/}
IEnumerator c(){/*代码*/}
IEnumerator d(){
IEnumerator iea=a();
IEnumerator ieb=b();
IEnumerator iec=c();
//注:此处使用的是单个|运算符
而(iea.MoveNext()| ieb.MoveNext()| iec.MoveNext()){
收益返回空;
}
打印(“全部”);
}
请参阅此处有关
|
运算符的文档

它基本上是一个
|
操作符,但它将计算所有表达式,从而有效地推进每个迭代器,即使已经完成了另一个迭代器。

这是否回答了您的问题?不。我知道,
yield startcroutine(a())
等待一个协同程序完成,但我想同时启动所有协同程序,并行执行。每个进程都有自己的持续时间,当最后一个进程结束时,
d
应该打印“全部结束”。协同进程本质上是单线程的。就其本质而言,它们不能“并行”运行。你需要线程that@Draco18s不完全是。协程既是单线程的,也是某种(非并发的)并行的。它们基本上是枚举器(执行步骤等)。真正的问题是:如何判断协同过程何时结束。@AndrewŁukasik你说得有点对。但认为它们“并行执行”是错误的。在任何情况下,等待协同路由完成的唯一方法是让调用方法成为协同路由(或编写自己的标志系统)。调用
wait a()时不需要使用
startcroutine
?上面的代码是我写的所有代码,所以没有。但是这个包是这样工作所必需的,因为它公开了正确的扩展methods@jrmgx协同程序将并行运行。“全部”将在3秒后打印。答案是正确的,并将并行运行。将按如下顺序运行:return yield startcroutine(a())@Biswadepsarkar您忘记了协程中的return语句,变量名和函数名相互冲突。也许你想解决这个问题,让人们更容易复制/粘贴并测试它。干杯。@biswadepsarkar您的确是对的,请注意
返回产生新的xxx
的语法是错误的,应该是
产生返回xxx
。除了今天我很高兴学到了一些新东西:)@jrmgx很高兴,你喜欢我的答案!我已经更新了答案。