并行开发 —— 第六篇 异步编程模型
在.net里面异步编程模型由来已久,相信大家也知道Begin/End异步模式和事件异步模式,在task出现以后,这些东西都可以被task包装
起来,可能有人会问,这样做有什么好处,下面一一道来。
一: Begin/End模式
1: 委托
在执行委托方法的时候,我们常常会看到一个Invoke,同时也有一对你或许不常使用的BeginInvoke,EndInvoke方法对,当然Invoke方法
是阻塞主线程,而BeginInvoke则是另开一个线程。
1 class Program2 {3 static void Main(string[] args)4 {5 var func = new Func<string, string>(i => { return i + "i can fly"; });6 7 var state = func.BeginInvoke("yes,", Callback, func);8 9 Console.Read(); 10 } 11 12 static void Callback(IAsyncResult async) 13 { 14 var result = async.AsyncState as Func<string, string>; 15 16 Console.WriteLine(result.EndInvoke(async)); 17 } 18 }
下面我们用task包装一下
1 class Program2 {3 static void Main(string[] args)4 {5 var func = new Func<string, string>(i =>6 {7 return i + "i can fly";8 });9 10 Task<string>.Factory.FromAsync(func.BeginInvoke, func.EndInvoke, "yes,", null).ContinueWith 11 (i => 12 { 13 Console.WriteLine(i.Result); 14 }); 15 16 Console.Read(); 17 } 18 }
可以看出,task只要一句就搞定,体现了task的第一个优点:简洁。
2:流
我们发现在Stream抽象类中提供了这样两对BeginRead/EndRead,BeginWrite/EndWrite(异步读写)的方法,这样它的n多继承类都可以
实现异步读写,下面举个继承类FileStream的例子。
1 static void Main(string[] args)2 {3 var path = "C://1.txt";4 5 FileStream fs = new FileStream(path, FileMode.Open);6 7 FileInfo info = new FileInfo(path);8 9 byte[] b = new byte[info.Length]; 10 11 var asycState = fs.BeginRead(b, 0, b.Length, (result) => 12 { 13 var file = result.AsyncState as FileStream; 14 15 Console.WriteLine("文件内容:{0}", Encoding.Default.GetString(b)); 16 17 file.Close(); 18 19 }, fs); 20 21 Console.WriteLine("我是主线程,我不会被阻塞!"); 22 23 Console.Read(); 24 }
我们用task包装一下
1 static void Main(string[] args)2 {3 var path = "C://1.txt";4 5 FileStream fs = new FileStream(path, FileMode.Open);6 7 FileInfo info = new FileInfo(path);8 9 byte[] b = new byte[info.Length]; 10 11 Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, b, 0, b.Length, null, TaskCreationOptions.None) 12 .ContinueWith 13 (i => 14 { 15 Console.WriteLine("文件内容:{0}", Encoding.Default.GetString(b)); 16 }); 17 18 Console.WriteLine("我是主线程,我不会被阻塞!"); 19 20 Console.Read(); 21 }
其实看到这里,我们并没有发现task还有其他的什么优点,但是深入的想一下其实并不是这么回事,task能够游刃于线程并发和同步,而原始的异步
编程要实现线程同步还是比较麻烦的。
假如现在有这样的一个需求,我们需要从3个txt文件中读取字符,然后进行倒序,前提是不能阻塞主线程。如果不用task的话我可能会用工作线程
去监视一个bool变量来判断文件是否全部读取完毕,然后再进行倒序,我也说了,相对task来说还是比较麻烦的,这里我就用task来实现。
1 class Program2 {3 static byte[] b;4 5 static void Main()6 {7 string[] array = { "C://1.txt", "C://2.txt", "C://3.txt" };8 9 List<Task<string>> taskList = new List<Task<string>>(3); 10 11 foreach (var item in array) 12 { 13 taskList.Add(ReadAsyc(item)); 14 } 15 16 Task.Factory.ContinueWhenAll(taskList.ToArray(), i => 17 { 18 string result = string.Empty; 19 20 //获取各个task返回的结果 21 foreach (var item in i) 22 { 23 result += item.Result; 24 } 25 26 //倒序 27 String content = new String(result.OrderByDescending(j => j).ToArray()); 28 29 Console.WriteLine("倒序结果:"+content); 30 }); 31 32 Console.WriteLine("我是主线程,我不会被阻塞"); 33 34 Console.ReadKey(); 35 } 36 37 //异步读取 38 static Task<string> ReadAsyc(string path) 39 { 40 FileInfo info = new FileInfo(path); 41 42 byte[] b = new byte[info.Length]; 43 44 FileStream fs = new FileStream(path, FileMode.Open); 45 46 Task<int> task = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, b, 0, b.Length, null, TaskCreationOptions.None); 47 48 //返回当前task的执行结果 49 return task.ContinueWith(i => 50 { 51 return i.Result > 0 ? Encoding.Default.GetString(b) : string.Empty; 52 }, TaskContinuationOptions.ExecuteSynchronously); 53 } 54 }
可以看出,task的第二个优点就是:灵活性。
这里可能就有人要问了,能不能用开多个线程用read以同步的形式读取,变相的实现文件异步读取,或许我们可能常听说程序优化后,最后出现的
瓶颈在IO上面,是的,IO是比较耗费资源的,要命的是如果我们开的是工作线程走IO读取文件,那么该线程就会一直处于等待状态,不会再接收任
何的外来请求,直到线程读取到文件为止,那么我们能不能用更少的线程来应对更多的IO操作呢?答案肯定是可以的,这里就设计到了”异步IO“的
概念,具体内容可以参照百科:http://baike.baidu.com/view/1865389.htm ,有幸的是beginXXX,endXXX完美的封装了“异步IO”。
二:事件模式
这个模式常以XXXCompleted的形式结尾,我们在文件下载这一块会经常遇到,这里我也举个例子。
1 class Program2 {3 static void Main(string[] args)4 {5 WebClient client = new WebClient();6 7 client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted);8 9 client.DownloadFileAsync(new Uri("http://imgsrc.baidu.com/baike/abpic/item/6a600c338744ebf844a0bc74d9f9d72a6159a7ac.jpg"), 10 "1.jpg", "图片下完了,你懂的!"); 11 12 Console.WriteLine("我是主线程,我不会被阻塞!"); 13 Console.Read(); 14 } 15 16 static void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 17 { 18 Console.WriteLine("\n" + e.UserState); 19 } 20 }
先前也说了,task是非常灵活的,那么针对这种异步模型,我们该如何封装成task来使用,幸好framework中提供了TaskCompletionSource来帮助
我们快速实现。
1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Text;5 using System.IO;6 using System.Threading.Tasks;7 using System.Net;8 using System.ComponentModel;9 10 namespace ConsoleApplication4 11 { 12 class Program 13 { 14 static void Main() 15 { 16 var downloadTask = DownLoadFileInTask( 17 new Uri(@"http://www.7720mm.cn/uploadfile/2010/1120/20101120073035736.jpg") 18 , "C://1.jpg"); 19 20 downloadTask.ContinueWith(i => 21 { 22 Console.WriteLine("图片:" + i.Result + "下载完毕!"); 23 }); 24 25 Console.WriteLine("我是主线程,我不会被阻塞!"); 26 27 Console.Read(); 28 } 29 30 static Task<string> DownLoadFileInTask(Uri address, string saveFile) 31 { 32 var wc = new WebClient(); 33 34 var tcs = new TaskCompletionSource<string>(address); 35 36 //处理异步操作的一个委托 37 AsyncCompletedEventHandler handler = null; 38 39 handler = (sender, e) => 40 { 41 if (e.Error != null) 42 { 43 tcs.TrySetException(e.Error); 44 } 45 else 46 { 47 if (e.Cancelled) 48 { 49 tcs.TrySetCanceled(); 50 } 51 else 52 { 53 tcs.TrySetResult(saveFile); 54 } 55 } 56 57 wc.DownloadFileCompleted -= handler; 58 }; 59 60 //我们将下载事件与我们自定义的handler进行了关联 61 wc.DownloadFileCompleted += handler; 62 63 try 64 { 65 wc.DownloadFileAsync(address, saveFile); 66 } 67 catch (Exception ex) 68 { 69 wc.DownloadFileCompleted -= handler; 70 71 tcs.TrySetException(ex); 72 } 73 74 return tcs.Task; 75 } 76 } 77 }
转载于:https://www.cnblogs.com/ShaYeBlog/archive/2012/09/12/2682109.html
并行开发 —— 第六篇 异步编程模型相关推荐
- 8天玩转并行开发——第六天 异步编程模型
原文:8天玩转并行开发--第六天 异步编程模型 在.net里面异步编程模型由来已久,相信大家也知道Begin/End异步模式和事件异步模式,在task出现以后,这些东西都可以被task包装 起来,可能 ...
- 【转】异步编程:.NET 4.5 基于任务的异步编程模型(TAP)
最近我为大家陆续介绍了"IAsyncResult异步编程模型 (APM)"和"基于事件的异步编程模式(EAP)"两种异步编程模型.在.NET4.0 中Micro ...
- 【转】1.8异步编程:.NET 4.5 基于任务的异步编程模型(TAP)
传送门:异步编程系列目录-- 最近我为大家陆续介绍了"IAsyncResult异步编程模型 (APM)"和"基于事件的异步编程模式(EAP)"两种异步编程模型. ...
- 【转】1.6异步编程:IAsyncResult异步编程模型 (APM)
传送门:异步编程系列目录-- 大部分开发人员,在开发多线程应用程序时,都是使用ThreadPool的QueueUserWorkItem方法来发起一次简单的异步操作.然而,这个技术存在许多限制.最大的问 ...
- 异步编程模型(C#5.0系列)
关于C#5.0的新功能--async和await关键字.它们是语法糖,可以简化异步操作代码的构造.当C#编译器看到一个await表达式时,它会生成代码,该代码自动异步地调用该表达式,然后立即将控制流返 ...
- [你必须知道的异步编程]——异步编程模型(APM)
本专题概要: 引言 你知道APM吗? 你想知道如何使用异步编程模型编写代码吗? 使用委托也可以实现异步编程,你知道否? 小结 一.引言 在前面的C#基础知识系列中介绍了从C#1.0--C#4.0中一些 ...
- C#异步编程-------异步编程模型(APM)
术语解释: APM 异步编程模型, Asynchronous Programming Model EAP 基于事件的异步编程模式, Event ...
- C# 线程知识--异步编程模型(APM)
在构建高性能.可伸缩的应用程序时,必定会采用异步操作来提升应用程序性能,改善用户体验,异步操作与线程池结合允许使用很少的线程执行许多的操作.CLR中提供了一种异步操作的模式即异步编程模式. 1.异步编 ...
- Agv、Rgv 车辆控制调度系统开发第六篇-流程控制器
Agv.Rgv 车辆控制调度系统开发第六篇-流程控制器 Agv.Rgv 车辆控制调度系统开发第六篇-流程控制器 Agv.Rgv 车辆控制调度系统开发第六篇-流程控制器 前言 一.PCS是什么? 二.P ...
最新文章
- Spring Boot 中实现跨域的 5 种方式,你一定要知道!
- Source Insight 经典教程
- 第十七届全国大学生智能汽车竞赛 沁恒微电子芯片推荐
- 一天搞定CSS:文本text--05
- JavaScript中常用的BOM属性
- 利用ABAP调试器脚本修改数据库表的值
- css 列 布局,CSS二列三列布局
- java 判断date为空_java – 如何检查JSONArray元素是否为空
- Linux负载均衡软件LVS(概念篇)
- StalinLocker:一款会在十分钟之后删除文件和数据的勒索软件
- hdu4757(可持久化 Trie )
- python cookbook 2字符串(2)
- 计算机体系结构实验1——计算机性能评测
- 基于单片机的十字路口交通灯设计(带左转带紧急按钮带调时间)
- 国庆专属头像、国旗专属头像一键生成源代码
- android仿qq聊天界面版带表情、相册、照相
- BPEL与XPDL的定位区别
- 上海落户计算机水平毕业研究生,2021上海积分落户应届毕业生直接落户上海
- jmeter参数化之函数助手
- Python获取Win7,Win10系统缩放大小
热门文章
- scrapy+mysql+pipeline+更新数据_python3+Scrapy爬虫实战(二)—— 使用pipeline数据保存到文本和数据库(mysql)...
- 手机mstsc远程工具_远程桌面连接,只需3步,轻松远程操控电脑!
- 《MySQL——主备切换流程与主备延迟》
- leetcode 51. N 皇后 思考分析
- 数据库mysql面试题 it_【模块三】数据库篇--MySQL面试题☞参考答案
- uva 1312——Cricket Field
- go语言扫描四位数可用域名
- Mac快捷键和实用技巧
- C++ 读取windows服务列表 与操作注册表
- mysql命令行如何建库_MySQL心得2--命令行方式建库和表