使用 Task 简化异步编程
.Net 传统异步编程概述
.NET Framework 提供以下两种执行 I/O 绑定和计算绑定异步操作的标准模式:
- 异步编程模型 (APM),在该模型中异步操作由一对 Begin/End 方法(如 FileStream.BeginRead 和 Stream.EndRead)表示。
- 基于事件的异步模式 (EAP),在该模式中异步操作由名为“操作名称Async”和“操作名称Completed”的方法/事件对(例如 WebClient.DownloadStringAsync 和 WebClient.DownloadStringCompleted)表示。 (EAP 是在 .NET Framework 2.0 版中引入的)。
Task 的优点以及功能
通过使用 Task 对象,可以简化代码并利用以下有用的功能:
- 在任务启动后,可以随时以任务延续的形式注册回调。
- 通过使用 ContinueWhenAll 和 ContinueWhenAny 方法或者 WaitAll 方法或 WaitAny 方法,协调多个为了响应 Begin_ 方法而执行的操作。
- 在同一 Task 对象中封装异步 I/O 绑定和计算绑定操作。
- 监视 Task 对象的状态。
- 使用 TaskCompletionSource 将操作的状态封送到 Task 对象。
使用 Task 封装常见的异步编程模式
1、 使用 Task 对象封装 APM 异步模式, 这种异步模式是 .Net 标准的异步模式之一, 也是 .Net 最古老的异步模式, 自 .Net 1.0 起就开始出现了,通常由一对 Begin/End 方法同时出现, 以 WebRequest 的 BeginGetResponse 与 EndGetResponse 方法为例:
var request = WebRequest.CreateHttp(UrlToTest);
request.Method = "GET";
var requestTask = Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse,
null
);
requestTask.Wait();
var response = requestTask.Result;
2、使用 Task 对象封装 EPM 异步模式, 这种模式从 .Net 2.0 开始出现, 同时在 Silverlight 中大量出现, 这种异步模式以 “操作名称Async” 函数和 “操作名称Completed” 事件成对出现为特征, 以 WebClient 的 DownloadStringAsync 方法与 DownLoadStringCompleted 事件为例:
var source = new TaskCompletionSource<string>();
var webClient = new WebClient();
webClient.DownloadStringCompleted += (sender, args) => {
if (args.Cancelled) {
source.SetCanceled();
return;
}
if (args.Error != null) {
source.SetException(args.Error);
return;
}
source.SetResult(args.Result);
};
webClient.DownloadStringAsync(new Uri(UrlToTest, UriKind.Absolute), null);
source.Task.Wait();
var result = source.Task.Result;
3、 使用 Task 对象封装其它非标准异步模式, 这种模式大量出现在第三方类库中, 通常通过一个 Action 参数进行回调, 以下面的方法为例:
void AddAsync(int a, int b, Action<int> callback)
封装方法与封装 EPM 异步模式类似:
var source = new TaskCompletionSource<int>();
Action<int> callback = i => source.SetResult(i);
AddAsync(, , callback);
source.Task.Wait();
var result = source.Task.Result;
通过上面的例子可以看出, 用 Task 对象对异步操作进行封装之后, 异步操作简化了很多, 只要调用 Task 的 Wait 方法, 可以直接获取异步操作的结果, 而不用转到回调函数中进行处理, 接下来看一个比较实际的例子。
缓冲查询示例
以 Esri 提供的缓冲查询为例, 用户现在地图上选择一个合适的点, 按照一定半径查询查询缓冲区, 再查询这个缓冲区内相关的建筑物信息, 这个例子中, 我们需要与服务端进行两次交互:
- 根据用户选择的点查询出缓冲区;
- 查询缓冲区内的建筑物信息;
这个例子在 GIS 查询中可以说是非常简单的, 也是很典型的, ESRI 的例子中也给出了完整的源代码, 这个例子的核心逻辑代码是:
_geometryService = new GeometryService(GeoServerUrl);
_geometryService.BufferCompleted += GeometryService_BufferCompleted; _queryTask = new QueryTask(QueryTaskUrl);
_queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; void MyMap_MouseClick(object sender, Map.MouseEventArgs e) {
// 部分代码省略, 开始缓冲查询
_geometryService.BufferAsync(bufferParams); } void GeometryService_BufferCompleted(object sender, GraphicsEventArgs args) {
// 部分代码省略, 获取缓冲查询结果, 开始查询缓冲区内的建筑物信息
_queryTask.ExecuteAsync(query);
} void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) {
// 将查询结果更新到界面上
}
这只是一个 GIS 开发中很简单的一个查询, 上面的代码却将逻辑分散在三个函数中, 在实际应用中, 与服务端的交互次数会更多, 代码的逻辑会分散在更多的函数中, 导致代码的可读性以及可维护性降低。 如果使用 Task 对象对这些任务进行封装, 那么整个逻辑将会简洁很多, GeometryService 和 QueryTask 提供的是 EPM 异步模式, 相应的封装方法如上所示, 最后, 用 Task 封装异步操作之后的代码如下:
void MyMap_MouseClick(object sender, Map.MouseEventArgs e) {
Task.Factory.StartNew(() => {
// 省略部分 UI 代码, 开始缓冲查询
var bufferParams = new BufferParameters() { /* 初始化缓冲查询参数 */};
var bufferTask = _geometryService.CreateBufferTask()
// 等待缓冲查询结果
bufferTask.Wait();
// 省略更新 UI 的代码, 开始查询缓冲区内的建筑物信息
var query = new Query() { /* 初始化查询参数 */ };
var queryExecTask = _queryTask.CreateExecTask(query);
queryExecTask.Wait();
// 将查询结果显示在界面上, 代码省略
});
}
从上面的代码可以看出, 使用 Task 对象可以把原本分散在三个函数中的逻辑集中在一个函数中即可完成, 代码的可读性、可维护性比原来增加了很多。
Task 能完成的任务远不止这些,比如并行计算、 协调多个并发任务等, 有兴趣的可以进一步阅读相关的 MSDN 资料。
使用 Task 简化异步编程的更多相关文章
- 使用任务Task 简化异步编程
使用任务简化异步编程 Igor Ostrovsky 下载代码示例 异步编程是实现与程序其余部分并发运行的较大开销操作的一组技术. 常出现异步编程的一个领域是有图形化 UI 的程序环境:当开销较大的操作 ...
- 利用反射快速给Model实体赋值 使用 Task 简化异步编程 Guid ToString 格式知多少?(GUID 格式) Parallel Programming-实现并行操作的流水线(生产者、消费者) c# 无损高质量压缩图片代码 8种主要排序算法的C#实现 (一) 8种主要排序算法的C#实现 (二)
试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段.现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增.那么我们就要新建一张合同历史表, ...
- 第十节:利用async和await简化异步编程模式的几种写法
一. async和await简介 PS:简介 1. async和await这两个关键字是为了简化异步编程模型而诞生的,使的异步编程跟简洁,它本身并不创建新线程,但在该方法内部开启多线程,则另算. 2. ...
- 把微信小程序异步API转为Promise,简化异步编程
把微信小程序异步API转化为Promise.用Promise处理异步操作有多方便,谁用谁知道. 微信官方没有给出Promise API来处理异步操作,而官方API异步的又非常多,这使得多异步编程会层层 ...
- 异步编程系列06章 以Task为基础的异步模式(TAP)
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- .Net Core WebAPI 基于Task的同步&异步编程快速入门
.Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...
- C# 异步编程3 TPL Task 异步程序开发
.Net在Framework4.0中增加了任务并行库,对开发人员来说利用多核多线程CPU环境变得更加简单,TPL正符合我们本系列的技术需求.因TPL涉及内容较多,且本系列文章为异步程序开发,所以本文并 ...
- C#异步编程
什么是异步编程 什么是异步编程呢?举个简单的例子: using System.Net.Http; using System.Threading.Tasks; using static System.C ...
- 谈谈c#中异步编程模型的变迁
大家在编程过程中都会用到一些异步编程的情况.在c#的BCL中,很多api都提供了异步方法,初学者可能对各种不同异步方法的使用感到迷惑,本文主要为大家梳理一下异步方法的变迁以及如何使用异步方法. Beg ...
随机推荐
- Android之自己定义checkbox样式
大部分情况下,我们在UI中并不採用android自带的checkbox复选框样式,这时候就须要我们自己定义自己的checkbox. 首先找两张checkbox背景图片.比方下图样子的: 然后在draw ...
- 基于SSH框架实际开发时遇到的问题及解决办法
1. 发现通过注解注入bean不起作用(对应的.java文件上没有'S'标记) 需要在pring .xml配置文件中加 <!-- 使用自动注解就必须配置加入自动扫描加载容器的包 --> & ...
- RabbitMQ之Exchange-4
RabbitMQ消息模型的核心思想是生产者不会将消息直接发送给队列.生产者通常不知道消息将会被哪些消费者接收,按照刚开始里介绍的rabbitMQ中所画的,生产者不是直接将消息发送给Queue么认识会交 ...
- 【mysql】windows7 安装 Mysql
From: http://jingyan.baidu.com/article/e52e3615a1128c40c70c5174.html 安装(解压) ZIP Archive版是免安装的.只要解压就行 ...
- DEDECMS自定义表单提交后的跳转链接修改方法
dedecms自定义表单,点击提交后,默认跳转到首页,我们打开plus/diy.php,里面有这样一段代码: 代码如下:if($dsql->executenonequery($query)) { ...
- Python学习笔记4—列表List
列表定义 Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. >>> a=['] >>> type(a) &l ...
- m2014-software->Word2010发布博客文章至Cnblogs
转自:http://www.cnblogs.com/xfiver/archive/2011/12/26/2301591.html 昨夜喝醉,今天早起梳理情绪,看下如何使用word2010直接写cnbl ...
- 二 Android Studio 打包EgretApp (开机画面、横竖屏、调试、和原生交互)
测试环境: Windows7 Egret Engine 5.0.14 Egret support 5.0.12 Android Studio 2.3 目录: 一 修改开机画面 二 横竖屏设置 三 修改 ...
- 【BZOJ3648】寝室管理 树分治
[BZOJ3648]寝室管理 Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T6 ...
- Jwt在javaweb项目中的应用核心步骤解读
1.引入jwt依赖 <!--引入JWT依赖,由于是基于Java,所以需要的是java-jwt--> <dependency> <groupId>io.jsonweb ...