马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
使用 async 和 await 举行异步编程
Task 异步编程模型 (TAP) 提供了对异步代码的抽象。您可以像往常一样将代码编写为语句序列。您可以阅读该代码,就好像每个语句在下一个语句开始之前完成一样。编译器执行许多转换,由于此中一些语句可能会开始工作并返回表现正在举行的工作的任务。
这就是此语法的目标:启用像语句序列一样读取的代码,但根据外部资源分配和任务完成时间以更复杂的次序执行。这类似于人们为包罗异步任务的流程提供指令的方式。在本文中,您将使用制作早餐的指令示例来相识 async 和 await 关键字怎样使推理包罗一系列异步指令的代码变得更轻易。您可以编写类似以下列表的指令来表明怎样做早餐:
- 倒一杯咖啡。
- 加热平底锅,然后煎两个鸡蛋。
- 煎三片培根。
- 烤两片面包。
- 在吐司上涂黄油和果酱。
- 倒一杯橙汁。
如果您有烹调经验,您可以异步执行这些指令。您可以先加热煎蛋锅,然后开始煎培根。将面包放入烤面包机,然后开始煎鸡蛋。在流程的每个步骤中,您都会启动一项任务,然后将留意力转移到预备好的任务上。
做早餐是异步非并行工作的一个很好的例子。一个人(或线程)可以处理所有这些任务。继续早餐类比,一个人可以通过在第一个任务完成之前启动下一个任务来异步做早餐。无论是否有人在看,烹调都会举行。一旦您开始加热煎蛋锅,您就可以开始煎培根。一旦培根开始煎,您就可以将面包放入烤面包机。
对于并行算法,您需要多个厨师(或线程)。一个做鸡蛋,一个做培根,依此类推。每个人都会专注于这一项任务。每个厨师(或线程)都会同步壅闭,等待培根翻转或面包片爆开。
现在,思量用 C# 语句编写的雷同指令:
- using System;
- 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 void Main(string[] args)
- {
- Coffee cup = PourCoffee();
- Console.WriteLine("coffee is ready");
- Egg eggs = FryEggs(2);
- Console.WriteLine("eggs are ready");
- Bacon bacon = FryBacon(3);
- Console.WriteLine("bacon is ready");
- Toast toast = ToastBread(2);
- ApplyButter(toast);
- ApplyJam(toast);
- Console.WriteLine("toast is ready");
- Juice oj = PourOJ();
- Console.WriteLine("oj is ready");
- Console.WriteLine("Breakfast is ready!");
- }
- 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 Toast ToastBread(int slices)
- {
- for (int slice = 0; slice < slices; slice++)
- {
- Console.WriteLine("Putting a slice of bread in the toaster");
- }
- Console.WriteLine("Start toasting...");
- Task.Delay(3000).Wait();
- Console.WriteLine("Remove toast from toaster");
- return new Toast();
- }
- private static Bacon FryBacon(int slices)
- {
- Console.WriteLine($"putting {slices} slices of bacon in the pan");
- Console.WriteLine("cooking first side of bacon...");
- Task.Delay(3000).Wait();
- for (int slice = 0; slice < slices; slice++)
- {
- Console.WriteLine("flipping a slice of bacon");
- }
- Console.WriteLine("cooking the second side of bacon...");
- Task.Delay(3000).Wait();
- Console.WriteLine("Put bacon on plate");
- return new Bacon();
- }
- private static Egg FryEggs(int howMany)
- {
- Console.WriteLine("Warming the egg pan...");
- Task.Delay(3000).Wait();
- Console.WriteLine($"cracking {howMany} eggs");
- Console.WriteLine("cooking the eggs ...");
- Task.Delay(3000).Wait();
- Console.WriteLine("Put eggs on plate");
- return new Egg();
- }
- private static Coffee PourCoffee()
- {
- Console.WriteLine("Pouring coffee");
- return new Coffee();
- }
- }
- }
复制代码
同步预备的早餐大约需要 30 分钟,由于总时间是每项任务的总和。
盘算机表明这些指令的方式与人类差别。盘算机将在每个语句上壅闭,直到工作完成,然后才继续执行下一个语句。这会导致早餐不令人满意。在完成前面的任务之前,后面的任务不会开始。制作早餐需要更长的时间,而且有些食物在上桌之前就会变冷。
如果您希望盘算机异步执行上述指令,则必须编写异步代码。
这些标题对于您本日编写的程序很紧张。当您编写客户端程序时,您希望 UI 能够相应用户输入。您的应用程序不应该让手机在从网络下载数据时出现冻结状态。当您编写服务器程序时,您不希望线程被壅闭。这些线程可能正在处理其他请求。在存在异步替代方案的情况下使用同步代码会侵害您以较低成本扩展的本领。您需要为这些被壅闭的线程付费。
成功的当代应用程序需要异步代码。在没有语言支持的情况下,编写异步代码需要回调、完成事件或其他手段,这会掩盖代码的原始意图。同步代码的优势在于其分步操作使其易于扫描和明确。传统的异步模型迫使您专注于代码的异步性质,而不是代码的根本操作。
|