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

/// <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; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿
        }

  

/// <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
        }

  

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; //这句话必须由主线程来执行,线程在同一时刻只能做一件事儿   -----(主线程在等待)----
        }

  测试用例

 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 @ 2021-12-06 15:24  wolfsocket  阅读(270)  评论(0编辑  收藏  举报