为建立中文知识库加块砖 ——中科大胡不归
问题描述
在C#中,我们在刚接触async+await时,发现使用async标记方法在返回类型为Task时,被ide提示如下:
Because this call is not awaited, execution of the current method continues
before the call is completed. Consider applying the 'await' operator to the result of the call.
因为未等待此调用,所以在调用完成之前,当前方法将继续执行。
比如如下这种调用:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Test02();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
private static async Task Test02()
{
await Task.Delay(10 * 1000);
Console.WriteLine("Done!");
}
编译检查你没有处理返回的Task,所以程序将不会等待Test02()的执行结果,由于Test02()异步执行,所以程序此时继续执行下一句打印。为什么会有这个警告呢,本文将尝试解释。
认识async+await
async+await是C#为我们异步编程接口,最简单的使用示例即:
private async Task Test02()
{
await GetLocalIp();
Console.WriteLine("Done!");
}
await接耗时方法,即可实现异步执行。当然此时你也会收获如上的警告。为避免这个警告,你需要处理返回Task。
精彩示例
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
DoStuff();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
private static void DoStuff()
{
var task = GetNameAsync();
// Set up a continuation BEFORE MainWorkOfApplicationIDontWantBlocked
var anotherTask = task.ContinueWith(r => {
Console.WriteLine("\n安排的明明白白:" + r.Result);
});
MainWorkOfApplicationIDontWantBlocked();
// OR wait for the result AFTER
var result = task.Result;
Console.WriteLine("\n苦心等来的结果:" + result);
}
private static void MainWorkOfApplicationIDontWantBlocked()
{
const string tang = "\n门前大桥下,\n游过一群鸭,\n快来快来数一数,\n二四六七八";
foreach (var cha in tang.ToCharArray())
{
Console.Write(cha);
Thread.Sleep(500);
}
}
private static async Task<string> GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
string lastname = await PromptForStringAsync("Enter your last name: ");
return firstname + lastname;
}
// contrived example (edited in response to Servy's comment)
private static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
MainWorkOfApplicationIDontWantBlocked是指不想被阻塞的主任务,这里是演唱儿歌。
GetNameAsync是同时允许用户输入姓名的异步程序。
var result = task.Result;中result是GetNameAsync返回类型string,当然task.Result也会阻塞进程。
效果演示
此示例实现主线程演唱儿歌不中断,同时用户能完成输入的异步任务。
返回Task与返回void
-
Task<T> 一个返回为Task<T>的异步方法的结果是可以被等待的,并在任务完成时,它会返回一个类型T的结果。
-
Task 一个返回为Task的异步方法的结果是可以被等待的,当任务完成时,任务的完成是可以被调度的。
-
void 一个返回为void的异步方法不能等待,这是一种“fire and forget(一x没)”的方法。它是异步工作的,我们无法知道何时完成。事件触发,处理程序执行,不会去“等待”事件处理程序返回的任务,因为事件处理程序也不会返回任务,即使它们返回了。什么地方可以使用这种方法呢?通常是不需要用户控制的地方。