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

news/2024/11/22 23:21:41/

 高效等待任务

可以使用 Task 类的方法来改进上述代码末尾的一系列 await 语句。其中一个 API 是 WhenAll,它返回一个 Task,该 Task 在其参数列表中的所有任务都完成后才完成,如以下代码所示: 

await Task.WhenAll(eggsTask, baconTask, toastTask);
Console.WriteLine("Eggs are ready");
Console.WriteLine("Bacon is ready");
Console.WriteLine("Toast is ready");
Console.WriteLine("Breakfast is ready!");

另一个选项是使用 WhenAny,它返回一个 Task<Task>,当其任何参数完成时,该 Task<Task> 就会完成。您可以等待返回的任务,因为您知道它已经完成。以下代码显示了如何使用 WhenAny 等待第一个任务完成,然后处理其结果。处理完已完成任务的结果后,您可以从传递给 WhenAny 的任务列表中删除该已完成任务。

var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{Task finishedTask = await Task.WhenAny(breakfastTasks);if (finishedTask == eggsTask){Console.WriteLine("Eggs are ready");}else if (finishedTask == baconTask){Console.WriteLine("Bacon is ready");}else if (finishedTask == toastTask){Console.WriteLine("Toast is ready");}await finishedTask;breakfastTasks.Remove(finishedTask);
}

接近结尾处,您会看到 await finishTask; 行。await Task.WhenAny 行不等待已完成的任务。它等待 Task.WhenAny 返回的任务。Task.WhenAny 的结果是已完成(或发生故障)的任务。您应该再次等待该任务,即使您知道它已完成运行。这就是您检索其结果或确保引发其故障的异常的方式。

经过所有这些更改后,代码的最终版本如下所示:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;namespace AsyncBreakfast
{// These classes are intentionally empty for the purpose of this example. They are simply marker classes for the purpose of demonstration, contain no properties, and serve no other purpose.internal class Bacon { }internal class Coffee { }internal class Egg { }internal class Juice { }internal class Toast { }class Program{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 breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };while (breakfastTasks.Count > 0){Task finishedTask = await Task.WhenAny(breakfastTasks);if (finishedTask == eggsTask){Console.WriteLine("eggs are ready");}else if (finishedTask == baconTask){Console.WriteLine("bacon is ready");}else if (finishedTask == toastTask){Console.WriteLine("toast is ready");}await finishedTask;breakfastTasks.Remove(finishedTask);}Juice oj = PourOJ();Console.WriteLine("oj is ready");Console.WriteLine("Breakfast is ready!");}static async Task<Toast> MakeToastWithButterAndJamAsync(int number){var toast = await ToastBreadAsync(number);ApplyButter(toast);ApplyJam(toast);return toast;}private static Juice PourOJ(){Console.WriteLine("Pouring orange juice");return new Juice();}private static void ApplyJam(Toast toast) =>Console.WriteLine("Putting jam on the toast");private static void ApplyButter(Toast toast) =>Console.WriteLine("Putting butter on the toast");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(3000);Console.WriteLine("Remove toast from toaster");return new Toast();}private static async Task<Bacon> FryBaconAsync(int slices){Console.WriteLine($"putting {slices} slices of bacon in the pan");Console.WriteLine("cooking first side of bacon...");await Task.Delay(3000);for (int slice = 0; slice < slices; slice++){Console.WriteLine("flipping a slice of bacon");}Console.WriteLine("cooking the second side of bacon...");await Task.Delay(3000);Console.WriteLine("Put bacon on plate");return new Bacon();}private static async Task<Egg> FryEggsAsync(int howMany){Console.WriteLine("Warming the egg pan...");await Task.Delay(3000);Console.WriteLine($"cracking {howMany} eggs");Console.WriteLine("cooking the eggs ...");await Task.Delay(3000);Console.WriteLine("Put eggs on plate");return new Egg();}private static Coffee PourCoffee(){Console.WriteLine("Pouring coffee");return new Coffee();}}
}

73e52c4b84784db999f779e09a30285a.png

异步准备早餐的最终版本大约需要 6 分钟,因为有些任务是并发运行的,并且代码同时监控多个任务,并且只在需要时采取行动。

最终代码是异步的。它更准确地反映了一个人如何做早餐。将前面的代码与本文中的第一个代码示例进行比较。从阅读代码中仍然可以清楚地看出核心操作。您可以像阅读本文开头的做早餐说明一样阅读此代码。async 和 await 的语言功能提供了每个人遵循这些书面说明所做的翻译:尽可能启动任务,不要阻止等待任务完成。

 


http://www.ppmy.cn/news/1549152.html

相关文章

春意盎然:基于Spring Boot的中药实验管理平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中药实验管理系统的相关信息成为必然。开发…

Seatunnel解决Excel中无法将数字类型转换成字符串类型以及源码打包

需求 需要实现将Excel中的数字类型的单元格像数据库中字符串类型的字段中推送 问题原因 Seatunnel在读取字段类型的时候都是使用强转的形式去获取数据的 假如说数据类型不一样的话直接强转就会报错 修改位置 org/apache/seatunnel/api/table/type/SeaTunnelRow.java org…

linux常用命令(网络相关)

目录 1. ping - 检查网络连通性 参数 示例 2. ifconfig - 配置网络接口 参数 示例 3. ip - 显示和操作路由、网络设备、接口等 参数 示例 4. netstat - 显示网络连接、路由表、接口统计等信息 参数 示例 5. ss - 更快的netstat替代品 参数 示例 6. nslookup - …

Oracle SQL plus设置篇

安装完Oracle和db之后&#xff0c;对于Oracle的各种交互命令窗口使用起来不是很得心应手&#xff0c;上下左右键包括删除操作都需要很麻烦&#xff0c;我们可以进行一些设置使我们更丝滑的使用Oracle的各种交互命令如SQL plus、RMAN、lsnrctl等。 1. 定义别名及配置环境变量 …

PgSQL即时编译JIT | 第1期 | JIT初识

PgSQL即时编译JIT | 第1期 | JIT初识 JIT是Just-In-Time的缩写&#xff0c;也就是说程序在执行的时候生成可以执行的代码&#xff0c;然后执行它。在介绍JIT之前&#xff0c;需要说下两种执行方式&#xff1a;解释执行和编译执行。其中解释执行是通过解释器&#xff0c;将代码逐…

Redis自动配置-序列化

背景说明 突然发现项目里的redis没有关于序列化的配置文件&#xff0c;引入了fastjson但是没有地方指定其为项目的redis序列化工具&#xff0c;由此展开的探索 1. 很久之前学springboot的时候听说过spring-boot-configuration-processor&#xff0c; 但是一直以为只是帮助识别…

EasyExcel在SpringBoot中的简单使用

简介 EasyExcel是一个基于Apache POI的Excel处理工具&#xff0c;它能够以简单的方式读写大型Excel文件&#xff0c;并且性能高效、内存占用低。在SpringBoot中集成EasyExcel可以极大地提高数据处理效率。以下是EasyExcel在SpringBoot中的简单使用教程。 步骤1&#xff1a;添…

【算法】动态规划中01背包问题解析

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…