所以我仍然试图理解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()
本身需要同步调用。
答案 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();
}
这将确保"程序完成"在任务二完成后打印。