.Net 异步编程

首先,异步编程没有我们想的那么复杂,不用害怕。
异步编程的核心是 Task 和 Task 对象,这两个对象对异步操作建模。 它们受关键字 async 和 await 的支持。 在大多数情况下模型十分简单:
对于 I/O 绑定代码,当你 await 一个操作,它将返回 async 方法中的一个 Task 或 Task。
对于 CPU 绑定代码,当你 await 一个操作,它将在后台线程通过 Task.Run 方法启动。
await 关键字有这奇妙的作用。 它控制执行 await 的方法的调用方,且它最终允许 UI 具有响应性或服务具有灵活性。
I/O 绑定示例:从 Web 服务下载数据
当我们点击按钮从 Web 服务下载某些数据时,不希望阻止 UI 线程。 只需执行如下操作即可轻松实现:

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

就是这么简单,不会在与任务对象的交互中停滞。
CPU 绑定示例:为游戏执行计算
假设你正在编写一个移动游戏,在该游戏中,按下某个按钮将会对屏幕中的许多敌人造成伤害。 执行伤害计算的开销可能极大,而且在 UI 线程中执行计算有可能使游戏在计算执行过程中暂停!
此问题的最佳解决方法是启动一个后台线程,它使用 Task.Run 执行工作,并 await 其结果。 这可确保在执行工作时 UI 能流畅运行。

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

识别 CPU 绑定和 I/O 绑定工作
前面两个示例演示如何将 async 和 await 用于 I/O 绑定和 CPU 绑定工作。如何判断是I/O绑定还是CPU绑定才是关键,因为这会极大影响代码性能,并可能导致某些构造的误用。
编写代码之前我们应该考虑两个问题:
1.你的代码是否会“等待”某些内容,例如数据库中的数据?
如果答案为“是”,则你的工作是 I/O 绑定。
2.你的代码是否要执行开销巨大的计算?
如果答案为“是”,则你的工作是 CPU 绑定。

如果你的工作为 I/O 绑定,请使用 async 和 await (而不使用 Task.Run)。 不应使用任务并行库 。
如果你的工作为 CPU 绑定,并且你重视响应能力,请使用 async 和 await,并在另一个线程上使用 Task.Run 生成工作。 如果该工作同时适用于并发和并行,则应考虑使用任务并行库。
此外,应始终对代码的执行进行测量。 例如,你可能会遇到这样的情况:多线程处理时,上下文切换的开销高于 CPU 绑定工作的开销。 每种选择都有折衷,应根据自身情况选择正确的折衷方案。
需要注意的地方
1.async方法需在其主体中具有await 关键字,否则它们将永不暂停!
2.作为一名顶尖程序员,应将“Async”作为后缀添加到所编写的每个异步方法名称中。
3.async void 应仅用于事件处理程序。因为没有返回类型,无法使用Task和Task<>,所以很难处理。
4.在 LINQ 表达式中使用异步 lambda 时请谨慎
5.
await 检索后台任务的结果
await Task.WhenAny 等待任何任务完成
await Task.WhenAll 等待所有任务完成
await Task.Delay Thread.Sleep 等待一段时间

猜你喜欢

转载自blog.csdn.net/weixin_39630549/article/details/100118312