传统的异步编程方式很复杂,直到 C# 5 引入了 async 编程模式。

.NET 内置的异步方法

async 和 await 关键字

async 和 await 是 C# 异步编程的核心,由它们定义的方法称为异步方法。

异步方法示例:

  1. // Three things to note in the signature:
  2. // - The method has an async modifier.
  3. // - The return type is Task or Task<T>.
  4. // Here, it is Task<int> because the return statement returns an integer.
  5. // - The method name ends in "Async."
  6. async Task<int> AccessTheWebAsync()
  7. {
  8. // You need to add a reference to System.Net.Http to declare client.
  9. HttpClient client = new HttpClient();
  10. // GetStringAsync returns a Task<string>. That means that when you await the task you'll get a string (urlContents).
  11. Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
  12. // You can do work here that doesn't rely on the string from GetStringAsync.
  13. DoIndependentWork();
  14. // The await operator suspends AccessTheWebAsync.
  15. // - AccessTheWebAsync can't continue until getStringTask is complete.
  16. // - Meanwhile, control returns to the caller of AccessTheWebAsync.
  17. // - Control resumes here when getStringTask is complete.
  18. // - The await operator then retrieves the string result from getStringTask.
  19. string urlContents = await getStringTask;
  20. // The return statement specifies an integer result.
  21. // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
  22. return urlContents.Length;
  23. }

什么是异步方法

  1. 方法签名包括 async 修饰符

  2. 约定方法名以 Async 为后缀

  3. 返回类型为以下几种之一

    1. Task
    2. Task
    3. void
  4. 方法内部至少包含一句 await 表达式:
    1. string urlContents = await getStringTask;
    2. await 表达式的意思是:方法在此处需要等待异步操作完成后才能继续向下执行。同时方法将被挂起,控制流返回给方法的调用者

异步编程的核心就是 Task 和 Task 对象,它们模拟了异步操作。

在 C# 中一个 Task 对象可以看作一个需要继续执行的操作,一个 Task 对象可以看作一个在将来会返回 T 类型值的操作。这就像承诺将在操作完成后返回 T 类型的值。

I/O 绑定异步操作示例:从 Web Service 下载数据

  1. private readonly HttpClient _httpClient = new HttpClient();
  2. downloadButton.Clicked += async (o, e) =>
  3. {
  4. // This line will yield control to the UI as the request
  5. // from the web service is happening.
  6. //
  7. // The UI thread is now free to perform other work.
  8. var stringData = await _httpClient.GetStringAsync(URL);
  9. DoSomethingWithData(stringData);
  10. };

CPU 绑定异步操作示例:执行计算

使用 Task.Run 来启动一个后台线程用于执行 CPU 绑定的操作。

  1. private DamageResult CalculateDamageDone()
  2. {
  3. // Code omitted:
  4. //
  5. // Does an expensive calculation and returns
  6. // the result of that calculation.
  7. }
  8. calculateButton.Clicked += async (o, e) =>
  9. {
  10. // This line will yield control to the UI while CalculateDamageDone()
  11. // performs its work. The UI thread is free to perform other work.
  12. var damageResult = await Task.Run(() => CalculateDamageDone());
  13. DisplayDamage(damageResult);
  14. };

.NET 类库内置的异步方法

通过 Async 后缀和返回类型为 Task(Task)来识别内置的异步方法。

网络操作相关的:

  1. HttpClient:发送 HTTP 请求,接收 HTTP 响应

  2. WebClient:收发数据

I/O 操作相关的:

  1. StreamWrite

  2. StreamReader

  3. XmlReader