C# 在所有任务完成之前防止异步方法返回

C# 在所有任务完成之前防止异步方法返回,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,因此,我仍在尝试理解异步/等待模式,但我也在尝试实现以下行为: 方法A调用方法B,该方法运行许多进程。其中一些进程可以在单独的线程上运行,而其他进程则在处理中,这样它们的返回值将在更接近需要时可用。方法B需要在所有这些过程完成之前不将控制权返回给调用方 以下是我正在使用的测试代码: static void Main(string[] args) { CallProc(); Console.WriteLine("Program finished"); Console.Rea

因此,我仍在尝试理解异步/等待模式,但我也在尝试实现以下行为:

方法A调用方法B,该方法运行许多进程。其中一些进程可以在单独的线程上运行,而其他进程则在处理中,这样它们的返回值将在更接近需要时可用。方法B需要在所有这些过程完成之前不将控制权返回给调用方

以下是我正在使用的测试代码:

static void Main(string[] args)
{
    CallProc();
    Console.WriteLine("Program finished");
    Console.ReadKey();
}

public static async Task CallProc()
{
    var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
    var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
    var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));

    // some process happens here

    var oneMessage = await one; // waits until one finishes and then snags it's value
    Console.WriteLine("Got message {0}", oneMessage);

    // some more stuff happens here

    var twoMessage = await two; // waits until two is finished and then snags it's value
    Console.WriteLine(twoMessage);

    // TODO: need to make sure that everything is completed before returning control to caller
}

public static string SomeSynchronousProcessIDontOwn(int delayTime, string message, bool delay = true)
{
    Console.WriteLine("Starting \"{0}\"", message);
    if(delay) Thread.Sleep(delayTime);
    return string.Format("Finished \"{0}\"", message);
}
现在,所发生的事情是,除了方法在所有操作完成之前返回外,所有操作都如我所期望的那样进行,因此输出显示“Program finished”,而“two”仍在运行


如何编写此代码,以便
CallProc()
可以异步执行这些任务,但延迟返回,直到完成所有任务。换句话说,
CallProc()
需要异步运行一些任务,但是
CallProc()
本身需要同步调用。

与其单独等待每个任务,为什么不在所有的时候使用
等待所有的任务呢

public static async Task CallProc()
{
    var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
    var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
    var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));

    // run synchronous tasks

    await Task.WhenAll(one, two, three);
}
如果希望使用
CallProc
块(即在所有任务完成之前不返回),请删除
async
声明,并改用
Task.WaitAll

public static void CallProc()
{
    // start tasks

    Task.WaitAll(one, two, three);
}

异步方法的思想是,它将立即(近似地)返回控制,当它概念上表示的操作完成时,它返回的任务将被标记为已完成

这意味着您的程序应该查看生成的任务以查看它何时完成,或者您首先不需要异步方法,并且您应该同步而不是异步地重新编写
CallProc

要使
CallProc
同步,只需删除
async
(并相应调整返回类型),然后等待每个任务,而不是使用
wait


如果
CallProc
确实应该是异步的,那么调用方应该在任务完成时(而不是在方法返回时)添加一个continuation(或使用
Wait
)来执行操作。

一种方法是对
CallProc
的结果调用
Wait()
。这将基本上等待
CallProc
返回的任务完成后再继续。在GUI应用程序中调用
Wait
,可能会导致死锁,但对于控制台应用程序来说,这是正常的

static void Main(string[] args)
{
    CallProc().Wait();
    Console.WriteLine("Program finished");
    Console.ReadKey();
}

这将确保在任务2完成后打印“Program finished”(程序已完成)。

您是否尝试过使用任务集合并使用task.WaitAll()方法?我尝试过。它产生了同样的结果。在一切都完成之前,控件被返回到main(),为什么不在最后等待三次呢?我不想把这作为一个答案,因为我不自信,但你不想让CallProc()等待吗;这与James的答案完全相同,但CallProc仍然可以异步调用。@Hammerstein这是我使用
whalll
的意图,我的想法是
CallProc
可以在外部等待。@Servy是的,但不是单独等待任务,为什么不等待它们全部完成呢?因为他在每次
等待之后都会做一些事情,除了等待下一个任务,或者是代码状态中的注释。@Servy OP没有提到这些任务需要以任何特定的顺序运行(我要求清楚)。它们不是以特定的顺序运行的。它们是并行执行的,但每个任务的结果都是按顺序执行的,不一定要等到其他任务完成后再执行。不管怎样,这不是重点。即使在所有
更方便的时候使用
,也不能解决他的程序不能按他期望的那样运行的事实,而且你建议的是一种纯粹的美学变化,不会影响他所关心的基本行为。因此,无论这在上下文中是否是有效的重构,这绝对不能回答问题。这绝不会阻止应用程序完成,而且单独使用
WaitAll
是不正确的。代码要么完全同步,要么完全异步,这一点很重要。按照你的建议混合这两个任务是非常糟糕的。所以我可能误解了,但我希望任务1、2和3立即开始运行(基本上让它们在处理过程中领先),然后只在需要时等待它们(即,如果你现在还没有完成,那么我会等待,否则给我结果并继续)。CallProc只被标记为async,这样我就可以在本文中使用wait关键字fashion@Sinaesthetic
Wait
Wait
的意思完全不同
Wait
表示“阻塞线程直到任务完成”。
Wait
表示“将执行控制权返回给调用者,并在等待的任务完成时执行此方法中的其余代码。”如果希望方法同步,则使用
Wait
。如果希望方法是异步的,可以使用
wait