Async Await 多线程等待 应用

不同框架的应用
///1.Winform--存在特殊处理
///2.ASP.NETCore---放心用
///3.控制台---放心用
///4.WPF----没试过---
///5.Core WebApi---放心用

Web开发 推荐

适用

跟第三方交互的(非托管资源,经常有async版本): 数据库openAsync-Redis Web请求-Api 文件读取 一用到底 Await为什么能提升吞吐—只负责发命令—然后就忙别的去了—不需 要等待---事儿完成前就不浪费资源---完成后再来线程处理---这里还 能复用

不适用

服务器本地计算(CPU密集型,托管资源 ) : 大数据加减乘除, 数据处理 反而可能影响性能 但是用了没啥事儿    

用法

1 async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用

2 await在方法体内部,只能放在async修饰的方法内,必须放在task前面

3 async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这 样才能await/wait)

4 带async+await后,返回值要多一层Task<>

硬件DMA技术, 带Async后缀的API 硬盘:接受命令—然后cpu忙自己的(线程)—写完/读完,会发中断信 号,CPU再继续处理,这就基于DMA异步操作,就是可以节约CPU 资源(线程)---- 线程启动-等着-当然很浪费 用了异步就不用等

 

 

 

4种等待方式

t.Wait()

Task.WaitAll()

t.Result

await t

Winform

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
/// <summary>
        ///异步方法: 正常执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnAsync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"**********************************btnAsync_Click******************************************");
            Debug.WriteLine($"This is btnAsync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
            long lResult = await this.CalculationAsync(1_000_000);
 
            Debug.WriteLine($"This is btnAsync_Click   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
            this.textAsyncResult.Text = lResult.ToString(); //这句话必须要主线程来执行的
            //更改控件的值,这里必须是(UI线程)主线程去执行;每次执行都能成功,说明每次这里都是主线程来执行的;跟Winform设计有关系;在Winform中,await后面的内容,都会让主线程来执行;
        }
        private async Task<long> CalculationAsync(long total)
        {
            var task = await Task.Run(() =>
            {
                Debug.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                long lResult = 0;
                for (int i = 0; i < total; i++)
                {
                    lResult += i;
                }
                Debug.WriteLine($"This is CalculationAsync   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
                return lResult;
            });
 
            return task; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿
        }

  

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
/// <summary>
        /// 同步方法:界面卡死了   新加一个线程变成三个线程等待 就不会死锁了
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"**********************************btnSync_Click******************************************");
            Debug.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            //var task = this.CalculationAsync(1_000_000);
            ////task.Wait();  //主线程阻塞等待
            ////1.主线程要等待  Winform特殊设计:await后面的内容必须由主线程执行;
            ////2.主线程在这儿也等待着在
            ////3.主线程无暇分身导致死锁
            ////4.怎么解决这个死锁?
            //long lResult = task.Result;//主线程阻塞等待,主线程在等结果,经过分析可以确定,界面卡死问题肯定是出在这儿
              
           long lResult = this.GetCalculationAsync(1_000_000);
 
            Debug.WriteLine($"This is btnSync_Click   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
            this.textSync.Text = lResult.ToString();
        }
        private long GetCalculationAsync(long total)
        {
            var taskLong = Task.Run(() =>
            {     //新开一个线程
                var task = this.CalculationAsync(total);
                long lResult = task.Result;//子线程
                return lResult;
            });
            return taskLong.Result;//主线程在等Result
        }

  

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
private void btnSync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"**********************************btnSync_Click******************************************");
            Debug.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            var task = this.CalculationAsync(1_000_000);
            //task.Wait();  //主线程阻塞等待
            ////1.主线程要等待  Winform特殊设计:await后面的内容必须由主线程执行;
            ////2.主线程在这儿也等待着在
            ////3.主线程无暇分身导致死锁
            ////4.怎么解决这个死锁?
            long lResult = task.Result;//主线程阻塞等待,主线程在等结果,经过分析可以确定,界面卡死问题肯定是出在这儿 ------等待---相互等待锁死
              
          // long lResult = this.GetCalculationAsync(1_000_000);     windform 中await后面必须由主线程完成
  
            Debug.WriteLine($"This is btnSync_Click   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
            this.textSync.Text = lResult.ToString();
        }
        private async Task<long> CalculationAsync(long total)
        {
            var task = await Task.Run(() =>
            {
                Debug.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                long lResult = 0;
                for (int i = 0; i < total; i++)
                {
                    lResult += i;
                }
                Debug.WriteLine($"This is CalculationAsync   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
                return lResult;
            });
 
            return task; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿   -----(主线程在等待)----
        }

  测试用例

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
public class AwaitAsyncTest
   {
       public static void Show()
       {
           #region ReadFile     //ReadFile对比Task:当然并发---10个线程 Async: 可以并发,但是并发不多---只有3个线程 Sync:同步,按顺序执行
           {
               Console.WriteLine("******************ReadFile***************");
               string path = "D:\\ZXWork\\Advanced15\\20210713Advanced15Course05Delegate.rar";
               int loopNum = 20;
               {
                   Console.WriteLine("*****************Async****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(ReadAsync(path, i));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               {
                   Console.WriteLine("*****************Task****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(ReadTask(path, i));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               //{
               //    Console.WriteLine("*****************Sync****************");
               //    Stopwatch stopwatch = new Stopwatch();
               //    stopwatch.Start();
               //    for (int i = 0; i < loopNum; i++)
               //    {
               //        ReadSync(path, i);
               //    }
               //    stopwatch.Stop();
               //    Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               //}
           }
           #endregion
 
           #region InvokeWeb    //InvokeWeb对比   Task:耗时长一些,并发不够高------10个线程---铁打的10个线程 Async:并发高,速度快----少于10个线程,没有影响并发,能重用就是没事儿了, 利用率高一些 Sync:串行的,耗时长
           {
               Console.WriteLine("******************InvokeWeb***************");
               string url = "http://localhost:8080/home/Sleep";
               int loopNum = 10;//5
               int second = 5;
               {
                   Console.WriteLine("*****************Async****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(WebAsync(url, i, second));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               {
                   Console.WriteLine("*****************Task****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(WebTask(url, i, second));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               {
                   Console.WriteLine("*****************Sync****************");
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       WebSync(url, i, second);
                   }
                   stopwatch.Stop();
                   Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
           }
           #endregion
 
           #region DoCalculation
           {
               Console.WriteLine("******************DoCalculation***************");
               int loopNum = 10;//5
               long total = 1_000_000_000;
               {
                   Console.WriteLine("*****************Task****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(DoCalculationTask(total, i));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Task耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               {
                   Console.WriteLine("*****************Async****************");
                   List<Task> taskList = new List<Task>();
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       taskList.Add(DoCalculationAsync(total, i));
                   }
                   Task.WaitAll(taskList.ToArray());
                   stopwatch.Stop();
                   Console.WriteLine($"Async耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
               Thread.Sleep(3000);
               {
                   Console.WriteLine("*****************Sync****************");
                   Stopwatch stopwatch = new Stopwatch();
                   stopwatch.Start();
                   for (int i = 0; i < loopNum; i++)
                   {
                       DoCalculationSync(total, i);
                   }
                   stopwatch.Stop();
                   Console.WriteLine($"Sync耗时{stopwatch.ElapsedMilliseconds}ms,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               }
           }
           #endregion
       }
 
       #region Read
       //await后面也会开启线程---只要其中一个执行结束了,当前这个现场马上可能去执行其他的人
       private static async Task<byte[]> ReadAsync(string path, int num)
       {
           Console.WriteLine($"This is ReadAsync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = await File.ReadAllBytesAsync(path);
                //这里读取文件:文件--比较大,也是耗好性能--计算机肯定回卡,主线程到这儿相当于说是告诉帮助类库,要做什么事儿,主线程就跑了,在这类并没有开启新的线程---降低了线程的开启的数量;  也降低了CPU的负荷; 降低了服务器的运行负荷
           Console.WriteLine($"This is ReadAsync{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
 
       //铁定10个线程
       private static Task<byte[]> ReadTask(string path, int num)
       {
           Console.WriteLine($"This is ReadTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = Task.Run(() =>
           {
               Console.WriteLine($"This is ReadTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               return File.ReadAllBytes(path);
           });
           Console.WriteLine($"This is ReadTask{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
 
       private static byte[] ReadSync(string path, int num)
       {
           Console.WriteLine($"This is ReadSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = File.ReadAllBytes(path);
           Console.WriteLine($"This is ReadSync{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
       #endregion
 
       #region InvokeWebRequest
       private static string InvokeWebRequest(string url)
       {
           string html = null;
           try
           {
               HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;//模拟请求
               request.Timeout = 30 * 1000;//
               using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)//发起请求
               {
                   if (response.StatusCode != HttpStatusCode.OK)
                   {
                       Console.WriteLine($"抓取{url}地址返回失败,response.StatusCode为{response.StatusCode}");
                   }
                   else
                   {
                       StreamReader sr = new StreamReader(response.GetResponseStream());
                       html = sr.ReadToEnd();//读取数据
                   }
               }
           }
           catch (WebException ex)
           {
               if (ex.Message.Equals("远程服务器返回错误: (306)。"))
               {
                   Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误: (306)");
                   html = null;
               }
           }
           catch (Exception ex)
           {
               Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误{ex.Message}");
               html = null;
           }
           return html;
       }
 
       private static async Task<string> InvokeWebRequestAsync(string url)
       {
           string html = null;
           try
           {
               HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;//模拟请求
               request.Timeout = 30 * 1000;//     //request.GetResponseAsync异步版本的发起请求
               using (HttpWebResponse response = (await request.GetResponseAsync()) as HttpWebResponse)//发起请求
               {
                   if (response.StatusCode != HttpStatusCode.OK)
                   {
                       Console.WriteLine($"抓取{url}地址返回失败,response.StatusCode为{response.StatusCode}");
                   }
                   else
                   {
                       StreamReader sr = new StreamReader(response.GetResponseStream());
                       return await sr.ReadToEndAsync();//异步
                   }
               }
           }
           catch (WebException ex)
           {
               if (ex.Message.Equals("远程服务器返回错误: (306)。"))
               {
                   Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误: (306)");
                   html = null;
               }
           }
           catch (Exception ex)
           {
               Console.WriteLine($"抓取{url}地址返回失败,远程服务器返回错误{ex.Message}");
               html = null;
           }
           return html;
       }
 
       private static async Task<string> WebAsync(string url, int num, int second)
       {
           url = $"{url}?loop={num}&type=Async&second={second}";
           Console.WriteLine($"This is InvokeAsync{url} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = await InvokeWebRequestAsync(url);
           Console.WriteLine($"This is InvokeAsync{url}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
 
       private static Task<string> WebTask(string url, int num, int second)
       {
           url = $"{url}?loop={num}&type=Task&second={second}";
           Console.WriteLine($"This is WebTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = Task.Run(() =>
           {
               Console.WriteLine($"This is WebTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               return InvokeWebRequest(url);
           });
           Console.WriteLine($"This is WebTask{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
       private static string WebSync(string url, int num, int second)
       {
           url = $"{url}?loop={num}&type=Sync&second={second}";
           Console.WriteLine($"This is WebSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = InvokeWebRequest(url);
           Console.WriteLine($"This is WebSync{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
       #endregion
 
       #region DoCalculation CPU密集型
       private static long Calculation(long total)
       {
           long lResult = 0;
           for (int i = 0; i < total; i++)
           {
               lResult += i;
           }
           return lResult;
       }
 
       private static async Task<long> CalculationAsync(long total)
       {
           return await Task.Run(() =>
            {
                long lResult = 0;
                for (int i = 0; i < total; i++)
                {
                    lResult += i;
                }
                return lResult;
            });
       }
 
       private static async Task<long> DoCalculationAsync(long total, int num)
       {
           Console.WriteLine($"This is DoCalculationAsync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = await CalculationAsync(total);
           Console.WriteLine($"This is DoCalculationAsync{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
 
       private static Task<long> DoCalculationTask(long total, int num)
       {
           Console.WriteLine($"This is DoCalculationTask{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = Task.Run(() =>
           {
               Console.WriteLine($"This is DoCalculationTask Ing,ThreadId={Thread.CurrentThread.ManagedThreadId}");
               return Calculation(total);
           });
           Console.WriteLine($"This is DoCalculationTask{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
       private static long DoCalculationSync(long total, int num)
       {
           Console.WriteLine($"This is DoCalculationSync{num} Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           var result = Calculation(total);
           Console.WriteLine($"This is DoCalculationSync{num}   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           return result;
       }
       #endregion
   }
posted @   wolfsocket  阅读(278)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示