微网站怎么制作,设计官网公司,做网站导航怎么调整大小,网站一般的后台缘起最近在看《深入解析C##xff08;第4版#xff09;》这本书#xff0c;看到了第五章#xff0c;这一章节是关于异步。之前对异步这个概念只能算是一知半解#xff0c;了解了它的概念和用法#xff0c;但是对它的实际场景和为了解决什么问题而诞生的是不太清楚的。于是… 缘起最近在看《深入解析C#第4版》这本书看到了第五章这一章节是关于异步。之前对异步这个概念只能算是一知半解了解了它的概念和用法但是对它的实际场景和为了解决什么问题而诞生的是不太清楚的。于是乎就和小伙伴之间有了一场讨论。概念一般来说对方法的调用都是同步执行的。例如在线程执行体内即线程的调用函数中方法的调用就是同步执行的。如果方法需要很长的时间来完成比方说从Internet加载数据的方法调用者线程将被阻塞直到方法调用完成。这时候为了避免调用者线程被阻塞这时候就需要用到异步编程了。异步编程可以解决线程因为等待独占式任务而导致的阻塞问题。探索探索过程中参考了《微软官方文档》《I/O Threads Explained》。例子说明官方以一个做早餐的例子来解释了什么叫同步并行和异步。假设做一个早餐需要完成7个步骤倒一杯咖啡。加热平底锅然后煎两个鸡蛋。煎三片培根。烤两片面包。在烤面包上加黄油和果酱。倒一杯橙汁。同步执行同步执行是指只有完成上一个任务才会开始下一个任务同时将阻塞当前线程执行其他操作直至任务全部完成代码例子如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89// 鉴于我用的是vs2022,可能控制台程序的代码在旧版本的vs上无法直接运行需要补充对应的main函数
MakeBreakfast();static void MakeBreakfast()
{var cup PourCoffee();Console.WriteLine(coffee is ready);var eggs FryEggs(2);Console.WriteLine(eggs are ready);var bacon FryBacon(3);Console.WriteLine(bacon is ready);var toast ToastBread(2);ApplyButter(toast);ApplyJam(toast);Console.WriteLine(toast is ready);var oj PourOJ();Console.WriteLine(oj is ready);Console.WriteLine(Breakfast is ready!);
}static Juice PourOJ()
{Console.WriteLine(Pouring orange juice);return new Juice();
}static void ApplyJam(Toast toast) Console.WriteLine(Putting jam on the toast);static void ApplyButter(Toast toast) Console.WriteLine(Putting butter on the toast);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();
}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();
}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();
}static Coffee PourCoffee()
{Console.WriteLine(Pouring coffee);return new Coffee();
}public class Juice { }public class Bacon { }public class Egg { }public class Coffee { }public class Toast { }同步执行的总耗时是每个任务耗时的总和。此外因为是同步执行的原因在开始制作一份早餐的时候如果此时又有一份制作早餐的请求过来是不会开始制作的。如果是客户端程序使用同步执行耗时时间长的操作会导致UI线程被阻塞导致UI线程无法响应用户操作直至操作完成后UI线程才相应用户的操作。异步执行异步执行是指在遇到await的时候才需要等待异步操作完成然后往下执行但是不会阻塞当前线程执行其他操作。代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60await MakeBreakfastAsync();static async Task MakeBreakfastAsync()
{var cup PourCoffee();Console.WriteLine(coffee is ready);var eggs await FryEggsAsync(2);Console.WriteLine(eggs are ready);var bacon await FryBaconAsync(3);Console.WriteLine(bacon is ready);var toast await ToastBreadAsync(2);ApplyButter(toast);ApplyJam(toast);Console.WriteLine(toast is ready);var oj PourOJ();Console.WriteLine(oj is ready);Console.WriteLine(Breakfast is ready!);
}static async TaskToast ToastBreadAsync(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 await Task.FromResult(new Toast());
}static TaskBacon FryBaconAsync(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 Task.FromResult(new Bacon());
}static TaskEgg FryEggsAsync(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 Task.FromResult(new Egg());
}上面代码只是为了避免堵塞当前的线程并没有真正用上异步执行的某些关键功能所以在耗时上是相差不远的但是这时候如果在接受了一份制作早餐的请求还未完成的时候又有一份制作早餐的请求过来是可能会开始制作另一份早餐的。改善后的异步执行代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25await MakeBreakfastBetterAsync();static async Task MakeBreakfastBetterAsync()
{Coffee cup PourCoffee();Console.WriteLine(Coffee is ready);TaskEgg eggsTask FryEggsAsync(2);TaskBacon baconTask FryBaconAsync(3);TaskToast 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!);
}异步方法的逻辑没有改变只是调整了一下代码的执行顺序一开始就调用了三个异步方法只是在await语句后置了而不是上面那段代码一样执行了就在那里等待任务完成而是会去进行其他的后续操作直至后续操作需要用到前面任务执行结果的时候才去获取对应的执行结果如果没有执行完成就等待执行完成才继续后续的操作。异步执行并不总是需要另一个线程来执行新任务。并行编程是异步执行的一个子集。并行编程并行编程调用多个线程同时去执行任务例如需要制作五份早餐同步和异步的方法都是需要循环调用相应的MakeBreakfast方法和MakeBreakfastBetterAsync方法五次才能制作完成。而并行编程也就是多线程可以一次性创建五个线程分别制作一份早餐从而大大缩短了所需要的时间。代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34DateTime beforeDT DateTime.Now;
for (int i 0; i 5; i)
{MakeBreakfast();
}
DateTime afterDT DateTime.Now;
TimeSpan ts afterDT.Subtract(beforeDT);
Console.WriteLine($同步执行程序耗时: {ts.TotalMilliseconds}ms);beforeDT DateTime.Now;
for (int i 0; i 5; i)
{await MakeBreakfastBetterAsync();
}
afterDT DateTime.Now;
ts afterDT.Subtract(beforeDT);
Console.WriteLine($异步执行程序耗时: {ts.TotalMilliseconds}ms);beforeDT DateTime.Now;
await MakeBreakfastBetterMultiTask();
afterDT DateTime.Now;
ts afterDT.Subtract(beforeDT);
Console.WriteLine($并行编程程序耗时: {ts.TotalMilliseconds}ms);static async Task MakeBreakfastBetterMultiTask()
{Task[] tasks new Task[5];for (int i 0; i 5; i){tasks[i] new Task((parameter) MakeBreakfastBetterAsync().Wait(), aaa);tasks[i].Start();}Task.WaitAll(tasks);
}运行耗时结果如下相比之下显然能看出来之间的运行耗时差别还是有点大的。一个通俗的例子程序就像一个餐馆线程就像餐馆里面已有的厨师CPU就是调度厨师的厨师长假设餐馆开业了厨师长只带了5个厨师餐馆接到的订单有8份同步执行就是5个厨师分别处理5个订单后这期间他们会专心的去完成订单的菜而无视其他的事情直到完成订单厨师长才会分配新的订单给他们异步执行则是5个厨师在处理5个订单的期间如果厨师长发现他们有人处于空闲状态就会安排他们去执行剩下3个订单如果收到等待中的订单可以继续操作时厨师长会抽调厨师继续完成订单从而增加了餐馆处理订单的能力。而并行编程则是餐馆开业的时候告诉了厨师长需要8个厨师厨师长就带来了相应数量的厨师来处理订单。这就是这两天我对同步异步和并行之间的感悟。如有不对敬请指正推荐阅读《Kubernetes全栈架构师Kubeadm高可用安装k8s集群--学习笔记》《.NET 云原生架构师训练营模块一 架构师与云原生--学习笔记》《.NET Core开发实战第1课课程介绍--学习笔记》