多线程编程学习笔记——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", );
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", );
Task<string> task2 = GetInfoAsync("Task 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", );
Task<string> task4 = GetInfoAsync("Task 4", );
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 = ;
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线程。
- 在解决方案管理器中右键—>添加引用。。。,如下图。

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 = ;
var sw = new Stopwatch();
sw.Start();
for (int i = ; 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 = ;
var sw = new Stopwatch();
sw.Start();
for (int i = ; 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(三)的更多相关文章
- 多线程编程学习笔记——async和await(二)
接上文 多线程编程学习笔记——async和await(一) 三. 对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...
- 多线程编程学习笔记——async和await(一)
接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...
- 多线程编程学习笔记——使用异步IO(一)
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- 多线程编程学习笔记——异步调用WCF服务
接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...
- 多线程编程学习笔记——使用异步IO
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端
接上文 多线程编程学习笔记——使用异步IO 二. 编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...
- [Java123] JDBC and Multi-Threading 多线程编程学习笔记
项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5 :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...
- Java多线程编程(学习笔记)
一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...
- python学习笔记 async and await
用asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from调用另一个coroutine实现异 ...
随机推荐
- 配置ssh免密码登陆
以root账户为例 准备两台以上的Linux服务器,我这里用的是s204,s205两台机器,多台同样的 先使用ssh登录试一下,如果没有安装则需要先安装一下 ssh s205会提示你输入密码 原理 ...
- EAS(学生管理系统)初建
一.确定开发使用的技术 本次开发EAS示例网站,使用Servlet+JSP+MySQL技术,其中包括使用bootstrap工具完成简易前端页面设计.所有数据实体与数据关系皆用数 ...
- [转载] HBase vs Cassandra:我们迁移系统的原因
转载自http://www.csdn.net/article/2010-11-29/282698 我的团队近来正在忙于一个全新的产品——即将发布的网络游戏www.FightMyMonster.com. ...
- 前端面试题系列(1):doctype作用 标准模式与兼容模式
1.doctype作用 <!DOCTYPE>声明位于HTML文档的第一行.处于<HTML>标签之前.告知浏览器的解析器用什么文档标准解析这个文档.DOCYTYPE不存在或格式不 ...
- SSM 配合 Mysql 数据库和代码数据源主从分离
大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够.到了数据业务层.数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器扛,如此多的数据库连接操作,数据库必然会崩溃,数据丢 ...
- ES6中class关键字
1 .介绍 //定义类 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + th ...
- 分享一篇vue项目规范
最近 Vue 用的比较多,而且因为公司里有实习生,当几个人写一个项目的时候,会出现很多问题,最麻烦的就是规范不统一,之前我有一篇文章是说, vue 是比较有规范的一种框架了,但是也会出现很多问题,所以 ...
- 【设计模式系列】之OO面向对象设计七大原则
1 概述 本章叙述面向向对象设计的七大原则,七大原则分为:单一职责原则.开闭原则.里氏替换原则.依赖倒置原则.接口隔离原则.合成/聚合复用原则.迪米特法则. 2 七大OO面向对象设计 2.1 单一 ...
- MySQL .msi 安装失败改用.zip安装步骤
一开始官网下载.msi安装包,安装到配置server时无法启动,长时间卡在这里,无法继续下去.上网看了一下解决办法,发现用.zip安装包进行安装比较简单可靠. 一.利用.msi安装包安装失败后的处理 ...
- 第十一章 泛型算法 C++ PRIMER
vector<int>::const_iterator result = find(vector.begin(). vector.end(),search_value); 如果查找失败,分 ...