async和await的使⽤总结~竟然⼀直⽤错了c#中的async和await
的使⽤。。
对于c#中的async和await的使⽤,没想到我⼀直竟然都有⼀个错误。。
。。还是总结太少,这⾥记录下。
这⾥以做早餐为例
流程如下:
1. 倒⼀杯咖啡。
2. 加热平底锅,然后煎两个鸡蛋。
3. 煎三⽚培根。
4. 烤两⽚⾯包。
5. 在烤⾯包上加黄油和果酱。
6. 倒⼀杯橙汁。
当使⽤同步⽅式实现时,代码是这样的:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
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!");
Console.WriteLine($"totol time:{sw.ElapsedMilliseconds/1000}");
Console.ReadKey();
}
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("");
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 ");
Task.Delay(3000).Wait();
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side ");
Task.Delay(3000).Wait();
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static Egg FryEggs(int howMany)
{
Console.WriteLine("Warming the ");
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();
}
}
class Coffee { }
class Egg { }
class Bacon { }
class Toast { }
class Juice { }
}
运⾏效果如下:
或表⽰为这样
同步准备的早餐⼤约花费了 30 分钟,因为总耗时是每个任务耗时的总和。这⾥的total time只是⽤来表⽰记录下程序运⾏的时间。⽽我以前写的异步代码是这样的:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static async void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Egg eggs = await FryEggsAsync(2);
Console.WriteLine("eggs are ready");
Bacon bacon = await FryBaconAsync(3);
Console.WriteLine("bacon is ready");
Toast toast = await ToastBreadAsync(2);
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
Console.WriteLine($"totol time:{sw.ElapsedMilliseconds/1000}");
Console.ReadKey();
}
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();
await和async使用方法}
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("");
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 ");
await Task.Delay(3000);
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side ");
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 ");
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();
}
}
class Coffee { }
class Egg { }
class Bacon { }
class Toast { }
class Juice { }
}
效果如下:
可以看出,这样编写的异步和最初同步版本的总共的耗时⼤致相同。
这是因为这段代码还没有利⽤异步编程的某些关键功能。
即上⾯的异步代码的使⽤在这⾥是不准确的。
可以看出,这段代码⾥⾯的打印输出与同步是⼀样的。
这是因为:在煎鸡蛋或培根时,此代码虽然不会阻塞,但是此代码也不会启动任何其他任务。就造成了异步煎鸡蛋的操作完成后,才会开始培根制作。
但是,对于这⾥⽽⾔,我不希望每个任务都按顺序依次执⾏。
最好是⾸先启动每个组件任务,然后再等待之前任务的完成。
例如:⾸先启动鸡蛋和培根。
同时启动任务
在很多⽅案中,你可能都希望⽴即启动若⼲独⽴的任务。然后,在每个任务完成时,你可以继续进⾏已经准备的其他⼯作。
就像这⾥同时启动煎鸡蛋,培根和烤⾯包。
我们这⾥对早餐代码做些更改。
正确的做法
第⼀步是存储任务以便在这些任务启动时进⾏操作,⽽不是等待:
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Task<Egg> eggsTask = FryEggsAsync(2);
Egg eggs = await eggsTask;
Console.WriteLine("eggs are ready");
Task<Bacon> baconTask = FryBaconAsync(3);
Bacon bacon = await baconTask;
Console.WriteLine("bacon is ready");
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
接下来,可以在提供早餐之前将⽤于处理培根和鸡蛋的await语句移动到此⽅法的末尾:
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Task<Egg> eggsTask = FryEggsAsync(2);
Task<Bacon> baconTask = FryBaconAsync(3);
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Egg eggs = await eggsTask;
Console.WriteLine("eggs are ready");
Bacon bacon = await baconTask;
Console.WriteLine("bacon is ready");
Console.WriteLine("Breakfast is ready!");
运⾏效果如下:
或者
可以看出,这⾥⼀次启动了所有的异步任务。⽽你仅在需要结果时,才会等待每项任务。
这⾥异步准备的造成⼤约花费20分钟,这是因为⼀些任务可以并发进⾏。
⽽对于直接  Egg eggs = await FryEggsAsync(2); 的⽅式,适⽤于你只需要等待这⼀个异步操作结果,不需要进⾏其他操作的时候。与任务组合
吐司操作由异步操作(烤⾯包)和同步操作(添加黄油和果酱)组成。
这⾥涉及到⼀个重要概念:
异步操作后跟同步操作的这种组合也是⼀个异步操作。
也就是说,如果操作的任何部分是异步的,整个操作就是异步的。
代码如下:
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
所有,主要代码块现在变为:
static async Task Main(string[] args)
{

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。