多线程编程学习笔记——async和await

DotNet菜园 DotNet菜园     2022-10-06     115

关键词:

接上文 多线程编程学习笔记——async和await(一)

接上文 多线程编程学习笔记——async和await(二)

五、   处理异步操作中的异常

      本示例学习如何在异步函数中处理异常,学习如何对多个并行的异步操作使用await时聚合异常。

 1.程序示例代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; 

namespace ThreadAsyncDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(string.Format("-----    处理异步操作中的异常----"));
            Task t = AsyncProcess();
            t.Wait();       

            Console.Read();         

        } 

        async static Task AsyncProcess()
        {
            Console.WriteLine(string.Format("-----    1   单个异常处理----"));
            try
            {
               string result =await GetInfoAsync("Task 1", 2);
                Console.WriteLine(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("异常信息:{0}",ex.Message));
            }

            Console.WriteLine(string.Format("                   -------   ----"));
            Console.WriteLine(string.Format("-----    2   多个异常处理----"));
            Task<string> task1 = GetInfoAsync("Task 1", 3);
            Task<string> task2 = GetInfoAsync("Task 2",2);
            try
            {
                string[] results = await Task.WhenAll(task1, task2);
                Console.WriteLine((string.Format("结果数量:{0}",results.Length)));
                foreach (var item in results)
                {
                    Console.WriteLine(item);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("异常信息:{0}", ex.Message));
            }           

            Console.WriteLine(string.Format("                   -------   ----"));
            Console.WriteLine(string.Format("-----    3   多个异常处理 在AggregateException----"));
            Task<string> task3 = GetInfoAsync("Task 3", 3);
            Task<string> task4 = GetInfoAsync("Task 4", 2);
            Task<string[]> task5 = Task.WhenAll(task3, task4);
            try
            {
                string[] results5 = await task5;
                Console.WriteLine((string.Format("结果数量:{0}", results5.Length)));
                foreach (var item in results5)
                {
                    Console.WriteLine(item);
                }
            }
            catch
            {
                var aex = task5.Exception.Flatten(); //获取AggregateException
                var exs = aex.InnerExceptions;
                Console.WriteLine(string.Format("异常信息:{0}", exs.Count));
                int i = 0;
                foreach (var item in exs)
                {
                    i++;
                    Console.WriteLine(string.Format("       -----   {0}   ----",i));
                    Console.WriteLine(string.Format("异常信息:{0}", item.Message));
                }
            }
        } 

        async static Task<string> GetInfoAsync(string name,int second)
        {
            Console.WriteLine(string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工作线程是否是线程池中的线程:{2}", name, 
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread));
await Task.Delay(TimeSpan.FromSeconds(second)); throw new Exception(string.Format("{0} 抛出异常信息!", name)); } } }

2.程序运行结果,如下图。

 

      这个程序一共有三个场景来学习使用async与await时,关于异常处理的常见情况。

      第一种情况最简单,与常见的同步 代码几乎一样,我们只使用try catch即可获取异常信息。

     第二种情况是对一个以上的异步异常使用await时,则只能从aggregateexception对象中得到第一个异常。

      第三种情况中,我们使用aggregateException中的flatten方法将层级异常放入一个列表,并从中提取所有的底层异常。

六、   避免使用捕获的同步上下文

      本示例学习使用await来获取异步操作结果时,同步上下文行为的结节,并如何在何时关闭同步上下文流。

      默认情况下,await操作符会尝试捕获同步上下文,并在其中执行代码。使用await操作符不会发生死锁的情况,因为当等待结果时并不会阻塞UI线程。

  1. 在解决方案管理器中右键—>添加引用。。。,如下图。

       2.在“引用管理器”中找到System.Windows.Forms引用 ,并添加。如下图。

 

     3. 添加一个windows窗体。如下图。

 

      4. 在windows窗体中,添加按钮与文本框,界面如下图。

 

     6 .代码如下图。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; 

namespace ThreadAsyncDemo
{
    public partial class FormContext : Form
    {
        public FormContext()
        {
            InitializeComponent();
        } 

        async static Task<TimeSpan> TestNoContext()
        {
            const int interationsNumber = 100000;
            var sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < interationsNumber; i++)
            {
                var t = Task.Run(() => { });
                await t.ConfigureAwait(continueOnCapturedContext: false);
            }

            sw.Stop();
            return sw.Elapsed;
        }
        async static Task<TimeSpan> Test()
        {
            const int interationsNumber = 100000;
            var sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < interationsNumber; i++)
            {
                var t = Task.Run(() => { });
                await t;
            }
            sw.Stop();
            return sw.Elapsed; 

        } 

        private async void buttonAsync_Click(object sender, EventArgs e)
        {
            textBoxMsg.Text = "程序开始计算。。。。";
            TimeSpan resultWithContext = await Test();
            TimeSpan resultNoContext = await TestNoContext();
            //TimeSpan resultNoContext = await TestNoContext().ConfigureAwait(false);
            var sb = new StringBuilder();
            sb.AppendLine(string.Format("有上下文的运行时间:{0}",resultWithContext));
            sb.AppendLine(string.Format("没有上下文的运行时间:{0}", resultNoContext));
            sb.AppendLine(string.Format("有上下文的运行时间/没有上下文的运行时间:{0:0.00}", 
resultWithContext.TotalMilliseconds/ resultNoContext.TotalMilliseconds)); textBoxMsg.Text += "\r\n\r\n"; textBoxMsg.Text += sb.ToString(); } } }

      7.程序运行结果,如下图。

 

          这是一个windowform程序,我们在winfowform程序中创建了一个按钮点击事件,当点击这个按钮时,运行两个异步操作,其中一个异步操作使用了await操作符,别一个使用了带false参数值的configureAwait方法。False参数明确指出我们不能对其使用捕获的同步上下文来运行后续的代码。在每个操作中,我们计算了执行完成花费的时间,然后将各自的时间比较显示在屏幕上。

         从中我们发现await操作符花费了更多的时间来完成。这是因为我们向UI线程中放入了上千的后续操作任务,这就造成了使用消息循环来异步执行这些任务。而带有false参数值 的configureAwait方法是一个更高效的解决方式。

         我们还可以进行以下操作,当程序运行之后,在点击按钮后,等待结果时,可以随机拖拽应用程序窗口从一侧到另一侧,此时你注意一下,会发现捕获同步上下文的代码执行速度变慢了。如下图。

           

         最后,我们来看看相反的情况。在代码的点击事件中,取消注释行,并注释掉紧挨着它的前一行代码。运行程序,我们将看到多线程控制访问的异常。因为设置Label文本的代码没有放到捕捉的上下文中的,而是在线程池的工作 线程中执行。如下图。

 

 

 

多线程之异步编程:经典和最新的异步编程模型,async与await

经典的异步编程模型(IAsyncResult)最新的异步编程模型(async和await)将IAsyncInfo转换成Task将Task转换成IAsyncInfo示例1、使用经典的异步编程模型(IAsyncResult)实现一个支持异步操作的类Thread/Async/ClassicAsync.cs/**使用经典的异步编程... 查看详情

c#的多线程——使用async和await来完成异步编程(asynchronousprogrammingwithasyncandawait)

https://msdn.microsoft.com/zh-cn/library/mt674882.aspx侵删 更新于:2015年6月20日欲获得最新的VisualStudio2017RC文档,参考VisualStudio2017RCDocumentation。使用异步编程,你可以避免性能瓶颈和提升总体相应效率。然而,传统的异步方法代码的编... 查看详情

async和await

....NET版本为4.5。看很多朋友还是使用的Thread来使用异步多线程操作,基本上看不见有使用Async、Await进行异步编程的。各有所爱吧,其实都可以。只要正确使用就行,不过还是写了这篇文章推荐大家使用Async、Await。原因就是:可以... 查看详情

c#之多线程--任务概念以及使用示例(task|taskcompletionsource|async|await)(代码片段)

C#之异步多线程任务相关以及概念使用介绍一,相关关键字和运算符1.1Async/Await介绍和使用示例1.2Async/Await异步编程中的最佳做法二,Task类2.1Task定义2.2属性方法1.3Task使用三,TaskCompletionSource类3.1概念定义3.2属性函数3.3模拟... 查看详情

async和await之异步编程的学习

     async修改一个方法,表示其为异步方法。而await表示等待一个异步任务的执行。js方面,在es7中开始得以支持;而.net在c#5.0开始支持。本文章将分别简单介绍他们在js和.net中的基本用法。一、在js中的实现js... 查看详情

async和await之异步编程的学习

     async修改一个方法,表示其为异步方法。而await表示等待一个异步任务的执行。js方面,在es7中开始得以支持;而.net在c#5.0开始支持。本文章将分别简单介绍他们在js和.net中的基本用法。一、在js中的实现js... 查看详情

使用async和await的异步编程(代码片段)

官方文档遇到真正的await后,由新线程接管,即操作开始异步。不阻塞主线程classProgramstaticvoidMain(string[]args)Console.WriteLine($"主线程Thread.CurrentThread.ManagedThreadId");Console.WriteLine($"主线程Thread.CurrentThre 查看详情

多线程async&await

  .net4.0的Task已经让我们可以非常简单地使用多线程,并且可以有返回值,也可以支持线程的取消等操作,可谓已经很强大了。但.net4.5为我们带来了async&await,使得实现多线程的写法更简单,更优美,更符合线性思维。下面... 查看详情

c#多线程和异步——task和async/await详解(代码片段)

阅读目录一、什么是异步二、Task介绍1Task创建和运行 2Task的阻塞方法(Wait/WaitAll/WaitAny) 3Task的延续操作(WhenAny/WhenAll/ContinueWith) 4Task的任务取消(CancellationTokenSource)三、异步方法(async/await) 回到顶部一、什么是异步  ... 查看详情

异步编程之async和await(代码片段)

继续Dart异步编程的第五篇async和await。async和await是Dart异步编程用于简化异步API操作的两个关键字。它的作用就是能够将异步的代码使用同步的代码结构实现。相信学习过之前的Future和Stream的文章就知道,对于最终返回的值或者... 查看详情

异步编程async/await

...需要按照编写时的顺序严格执行,有时需要一在一个新的线程中运行一部分代码,有时无需创建新的线程,但是为了更好的利用单个线程的能力,需要改变代码的执行顺序。进程启动程序时,系统会在内存中创建一个新的进程。... 查看详情

.net的async和await

...关系是两兄弟,Task是父辈,Thread是爷爷辈,这就是.net多线程处理的东西,具体包括创建线程,线程结果返回,线程中止,线程中的异常处理1线程创建的几个方式staticvoidMain(string[]args){newThread(NewThread).Start();//这里需要注意:创建... 查看详情

多线程编程学习笔记——线程同步

接上文多线程编程学习笔记-基础(一)接上文多线程编程学习笔记-基础(二)接上文多线程编程学习笔记-基础(三)      就如上一篇文章(多线程编程学习笔记-基础(三))中的示例代码十,一样如果... 查看详情

多线程编程学习笔记——线程池

 接上文 多线程编程学习笔记——线程同步(一) 接上文多线程编程学习笔记——线程同步(二) 接上文多线程编程学习笔记——线程同步(三)       创建多线程操作... 查看详情

使用 async/await 会创建一个新线程吗?

】使用async/await会创建一个新线程吗?【英文标题】:Doestheuseofasync/awaitcreateanewthread?【发布时间】:2015-01-3116:01:20【问题描述】:我是TPL的新手,我想知道:C#5.0新增的异步编程支持(通过新的async和await关键字)与线程的创建有... 查看详情

多线程编程学习笔记-基础

接上文多线程编程学习笔记-基础(一)接上文多线程编程学习笔记-基础(二)九、向线程传递参数 1.代码如下。 usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading;//引入线程usingSystem.Diagnostics;na... 查看详情

c#中await和async的作用

...构成运行程序资源的集合。   在进程内部,有称为线程的内核对象,它代表的是真正的执行程序。系统会在Main方法的第一行语句就开始线程的执行。    线程:   ①默认情况,一个进程只包含一个线程,... 查看详情

多线程编程学习笔记——线程同步

接上文 多线程编程学习笔记——线程同步(一)接上文多线程编程学习笔记——线程同步(二)  七、使用Barrier类Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了Sig... 查看详情