防止异步方法返回,直到完成所有任务

时间:2014-07-29 20:26:30

标签: c# .net multithreading asynchronous async-await

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

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

3 个答案:

答案 0 :(得分:6)

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

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

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

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

答案 1 :(得分:5)

不是单独等待每个任务,而是使用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);
}

答案 2 :(得分:1)

执行此操作的一种方法是简单地在Wait()的结果上调用CallProc。这基本上等待CallProc返回的任务在继续之前完成。在GUI应用程序中调用Wait可能会导致死锁,但对于控制台应用程序则没问题。

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

这将确保"程序完成"在任务二完成后打印。