防止async方法在所有任务完成之前返回

本文关键字:返回 任务 async 方法 防止 | 更新日期: 2023-09-27 18:15:44

所以我仍然试图理解async/await模式,但我也试图实现以下行为:

A方法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()本身需要同步调用。

防止async方法在所有任务完成之前返回

异步方法的思想,也就是你所写的是,它将立即返回控制(大约),并且当它在概念上代表的操作完成时,它返回的任务将被标记为已完成。

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

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

如果CallProc真的应该是异步的,那么调用者应该在任务完成时添加一个延续(或使用await)来执行一个动作,而不是在方法返回时。

与其单独等待每个任务,不如使用WhenAll等待所有任务

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的结果简单地调用Wait()。这将在继续之前等待CallProc返回的任务完成。在GUI应用程序中调用Wait可能会导致死锁,但对于控制台应用程序来说,这是可以的。

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

这将确保在任务二完成后打印"Program finished"