废话少说,直接上代码
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();
await CreateMultipleTasksAsync();
resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
}
private async Task CreateMultipleTasksAsync()
{
// Declare an HttpClient object.
HttpClient client = new HttpClient();
// Create and start the tasks. As each task finishes, DisplayResults
// displays its length.
Task<int> download1 =
ProcessURL("http://msdn.microsoft.com", client);
Task<int> download2 =
ProcessURL("http://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
Task<int> download3 =
ProcessURL("http://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);
// Await each task.
int length1 = await download1;
int length2 = await download2;
int length3 = await download3;
int total = length1 + length2 + length3;
// Display the total count for the downloaded websites.
resultsTextBox.Text +=
string.Format("\r\n\r\nTotal bytes returned: {0}\r\n", total);
}
async Task<int> ProcessURL(string url, HttpClient client)
{
var byteArray = await client.GetByteArrayAsync(url);
DisplayResults(url, byteArray);
return byteArray.Length;
}
private void DisplayResults(string url, byte[] content)
{
// Display the length of each website. The string format
// is designed to be used with a monospaced font, such as
// Lucida Console or Global Monospace.
var bytes = content.Length;
// Strip off the "http://".
var displayURL = url.Replace("http://", "");
resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
}
界面上只有一个button和textbox,按下button后 程序将先进入“CreateMultipleTasksAsync”,然后再进入“ProcessURL”,大家知道打开网页是需要时间的如果此时线程一直等待网页的返回一定会有短暂的卡顿(线程阻塞),如果在方法前加了“async”即开始了异步方法,当调用await 唤醒(期间线程是空闲的,你点鼠标什么的也会有响应),此时线程继续执行方法。
关于await 微软官方的解释是:
await 运算符在异步方法应用于任务,以挂起执行方法,直到所等待的任务完成。 这个任务表示正在进行的工作。
在其中使用 await 的异步方法必须通过 async 关键字进行修改。使用 async 修饰符定义并且通常包含一个或多个 await 表达式的这类方法称为异步方法。
应用 await 运算符的任务通常是实现基于任务的异步模式的方法调用的返回值。示例包括 Task 或 Task<TResult> 类型的值。
在以下代码中,HttpClient 方法 GetByteArrayAsync 返回 Task<byte[]> (getContentsTask)。当任务完成时,任务约定生成实际字节数组。 await 运算符应用于 getContentsTask 以在 SumPageSizesAsync 中挂起执行,直到 getContentsTask 完成。同时,控制权会返回给 SumPageSizesAsync 的调用方。当 getContentsTask 完成之后,await 表达式计算为字节数组。
C#
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
System_CAPS_important重要事项
有关完整示例,请参阅演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)。可以从 Microsoft 网站上的开发人员代码示例下载该示例。该示例处于 AsyncWalkthrough_HttpClient 项目中。
如前面的示例中所示,如果 await 应用于返回 Task<TResult> 的方法调用结果,则 await 表达式的类型为 TResult。如果 await 应用于返回 Task 的方法调用结果,则 await 表达式的类型为 void。以下示例演示了差异。
C#
// Keyword await used with a method that returns a Task<TResult>.
TResult result = await AsyncMethodThatReturnsTaskTResult();
// Keyword await used with a method that returns a Task.
await AsyncMethodThatReturnsTask();
await 表达式不阻止正在执行它的线程。而是使编译器将剩下的异步方法注册为等待任务的延续任务。控制权随后会返回给异步方法的调用方。任务完成时,它会调用其延续任务,异步方法的执行会在暂停的位置处恢复。
await 表达式只能在由 async 修饰符标记的立即封闭方法体、lambda 表达式或异步方法中出现。术语“await”在该上下文中仅用作关键字。在其他位置,它会解释为标识符。在方法、lambda 表达式或匿名方法中,await 表达式不能在同步函数体、查询表达式、lock 语句块或不安全上下文中出现。
异常
大多数异步方法返回 Task 或 Task<TResult>。返回任务的属性携带有关其状态和历史记录的信息,如任务是否完成、异步方法是否导致异常或已取消以及最终结果是什么。 await 运算符可访问这些属性。
如果等待的任务返回异步方法导致异常,则 await 运算符会重新引发异常。
如果等待的任务返回异步方法取消,则 await 运算符会重新引发 OperationCanceledException。
处于故障状态的单个任务可以反映多个异常。例如,任务可能是对 Task.WhenAll 调用的结果。等待此类任务时,等待操作仅重新引发异常之一。但是,无法预测重新引发的异常。
有关异步方法中的错误处理的示例,请参阅 try-catch(C# 参考)。
下面的 Windows 窗体示例阐释如何在异步方法 WaitAsynchronouslyAsync 中使用 await。将该方法的行为与 WaitSynchronously 的行为进行对比。如果未向任务应用 await 运算符,WaitSynchronously 就会同步运行,而不管其定义中是否使用了 async 修饰符和在主体中是否调用了 Thread.Sleep。
C#
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Call the method that runs synchronously.
//string result = await WaitSynchronously ();
// Display the result.
textBox1.Text += result;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
// Add a using directive for System.Threading.
Thread.Sleep(10000);
return "Finished";
}