当前位置: 首页 > article >正文

windows C#-异步编程概述(三)

 任务组合

除了吐司之外,您同时准备好了早餐的所有东西。制作吐司是异步操作(烤面包)和同步操作(添加黄油和果酱)的组合。更新此代码说明了一个重要概念:

异步操作的组合,然后是同步工作,这是异步操作。换句话说,如果操作的任何部分是异步的,则整个操作都是异步的。

上述代码向您展示了您可以使用 Task 或 Task<TResult> 对象来保存正在运行的任务。在使用其结果之前,您需要等待每个任务。下一步是创建表示其他工作组合的方法。在提供早餐之前,您需要等待表示在添加黄油和果酱之前烤面包的任务。您可以使用以下代码表示该工作:

static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
    var toast = await ToastBreadAsync(number);
    ApplyButter(toast);
    ApplyJam(toast);

    return toast;
}

上述方法的签名中有 async 修饰符。这向编译器发出信号,表示此方法包含一个 await 语句;它包含异步操作。此方法表示烤面包,然后添加黄油和果酱的任务。此方法返回一个 Task<TResult>,表示这三个操作的组合。主要代码块现在变为:

static async Task Main(string[] args)
{
    Coffee cup = PourCoffee();
    Console.WriteLine("coffee is ready");

    var eggsTask = FryEggsAsync(2);
    var baconTask = FryBaconAsync(3);
    var toastTask = MakeToastWithButterAndJamAsync(2);

    var eggs = await eggsTask;
    Console.WriteLine("eggs are ready");

    var bacon = await baconTask;
    Console.WriteLine("bacon is ready");

    var toast = await toastTask;
    Console.WriteLine("toast is ready");

    Juice oj = PourOJ();
    Console.WriteLine("oj is ready");
    Console.WriteLine("Breakfast is ready!");
}

先前的更改说明了使用异步代码的重要技巧。通过将操作分离到返回任务的新方法中,可以编写任务。您可以选择何时等待该任务。您可以同时启动其他任务。

异步异常

到目前为止,您已经隐式假设所有这些任务都已成功完成。异步方法会引发异常,就像它们的同步对应方法一样。对异常和错误处理的异步支持与一般异步支持的目标相同:您应该编写像一系列同步语句一样读取的代码。任务在无法成功完成时会引发异常。客户端代码可以在等待启动的任务时捕获这些异常。例如,假设烤面包机在烤面包时着火。您可以通过修改 ToastBreadAsync 方法来模拟这种情况,以匹配以下代码:

private static async Task<Toast> ToastBreadAsync(int slices)
{
    for (int slice = 0; slice < slices; slice++)
    {
        Console.WriteLine("Putting a slice of bread in the toaster");
    }
    Console.WriteLine("Start toasting...");
    await Task.Delay(2000);
    Console.WriteLine("Fire! Toast is ruined!");
    throw new InvalidOperationException("The toaster is on fire");
    await Task.Delay(1000);
    Console.WriteLine("Remove toast from toaster");

    return new Toast();
}

编译上述代码时,您会收到有关无法访问代码的警告。这是故意的,因为一旦烤面包机着火,操作将无法正常进行。

进行这些更改后运行应用程序,您将输出类似于以下文本的内容:

Pouring coffee
Coffee is ready
Warming the egg pan...
putting 3 slices of bacon in the pan
Cooking first side of bacon...
Putting a slice of bread in the toaster
Putting a slice of bread in the toaster
Start toasting...
Fire! Toast is ruined!
Flipping a slice of bacon
Flipping a slice of bacon
Flipping a slice of bacon
Cooking the second side of bacon...
Cracking 2 eggs
Cooking the eggs ...
Put bacon on plate
Put eggs on plate
Eggs are ready
Bacon is ready
Unhandled exception. System.InvalidOperationException: The toaster is on fire
   at AsyncBreakfast.Program.ToastBreadAsync(Int32 slices) in Program.cs:line 65
   at AsyncBreakfast.Program.MakeToastWithButterAndJamAsync(Int32 number) in Program.cs:line 36
   at AsyncBreakfast.Program.Main(String[] args) in Program.cs:line 24
   at AsyncBreakfast.Program.<Main>(String[] args)

您会注意到,在烤面包机着火和观察到异常之间,有相当多的任务已经完成。当异步运行的任务抛出异常时,该任务就会出错。Task 对象保存在 Task.Exception 属性中抛出的异常。出错的任务在等待时会抛出异常。

需要了解两个重要的机制:异常如何存储在出错的任务中,以及当代码等待出错的任务时如何解包并重新抛出异常。

当异步运行的代码抛出异常时,该异常会存储在 Task 中。Task.Exception 属性是 System.AggregateException,因为在异步工作期间可能会抛出多个异常。任何抛出的异常都会添加到 AggregateException.InnerExceptions 集合中。如果该 Exception 属性为 null,则会创建一个新的 AggregateException,并且抛出的异常是集合中的第一个项目。

出错任务最常见的情况是 Exception 属性只包含一个异常。当代码等待出错的任务时,会重新抛出 AggregateException.InnerExceptions 集合中的第一个异常。这就是为什么此示例的输出显示 InvalidOperationException 而不是 AggregateException。提取第一个内部异常使使用异步方法与使用同步方法尽可能相似。当您的场景可能生成多个异常时,您可以在代码中检查 Exception 属性。

我们建议任何参数验证异常都从任务返回方法中同步出现。

继续之前,请在 ToastBreadAsync 方法中注释掉这两行,否则就再引发另一场灾难:

Console.WriteLine("Fire! Toast is ruined!");
throw new InvalidOperationException("The toaster is on fire");

http://www.kler.cn/a/400324.html

相关文章:

  • 十二:HTTP错误响应码:理解与应对
  • java版询价采购系统 招投标询价竞标投标系统 招投标公告系统源码
  • vscode文件重定向输入输出(竞赛向)
  • STM32完全学习——使用标准库点亮LED
  • java设计模式之 - 适配器模式
  • 帧中继原理与配置
  • 应用系统开发(12) Zync中实现数字相敏检波
  • 公众号登录报错问题处理
  • 【Pythonr入门第二讲】你好,世界
  • C# 属性与结构
  • 【机器学习】从马尔可夫链到CRF:全方位解析序列建模的核心技术
  • https://localhost/index 配置的nginx,一刷新就报404了
  • C++ 常见容器获取头元素的方法全览
  • 数据结构-二叉搜索树(Java语言)
  • 2.3 物理层设备
  • 无人机+无人车+机器狗:城市巷战突破技术详解
  • DataStream编程模型之数据源、数据转换、数据输出
  • 【蓝桥杯备赛】深秋的苹果
  • @quick-start/electron安装过程中的问题解决
  • CertiK安全调研报告:Web3.0桌面钱包的初步安全评估
  • vscode调试已经编译好的程序
  • ROS第九梯:ROS+VSCode+Python+C++自定义消息发布和订阅
  • ⚡️如何在 React 和 Next.js 项目里优雅的使用 Zustand
  • DAY30|贪心算法Part04|LeetCode:452. 用最少数量的箭引爆气球、435. 无重叠区间、763.划分字母区间
  • 【C++】用哈希表封装unordered_map和unordered_set
  • uni-app快速入门(十一)--常用JS API(上)