并行开发 —— 第六篇 异步编程模型

     

      在.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++相关

初始化列表中的初始化顺序1 class Printer{2 public:3 Printer(string name){cout<<name;}4 };5 class Container{6 public:7 Container():b("b"),a("a"){}8 Printer a;9 Printer b; 10 }; 11 12 int main…

PCB中加入logo

1、在网上找到任意一张图片 2、用Photoshop CS打开开始下载的图片 3、选择 图像→模式→灰度4、再选择 图像→模式→位图 5、弹出选项直接点击确定 6、选择保存BMP格式 7、打开Altium designer 6.9点击DXP→Run Script.. 8、点击Browse 打开路径为C:\Program Files\Altium Desi…

Java中的Unsafe在安全领域的一些应用总结和复现

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 目录* 0 前言 1 基本使用 1.1 内存级别修改值1.2 创建对象1.3 创建VM Anonymous Class 2 利用姿势 2.1 修改值以关闭RASP等…

Spring Boot中使用Swagger2构建强大的RESTful API文档

由于Spring Boot能够快速开发、便捷部署等特性&#xff0c;相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因&#xff0c;这些终端会共用很多底层业务逻辑&#xff0c;因此我们会抽象出这样一层来同时服务于多个…

关于公司没有公网IP也没有动态IP,如何远程办公呢?

2019独角兽企业重金招聘Python工程师标准>>> 迫于公司网络环境特殊&#xff0c;没有公网IP地址&#xff0c;也没有动态IP地址&#xff0c;其实就是园区分了一根内网固定IP的网线过来&#xff0c;这两天正巧有同事要外出办公&#xff0c;问题来了&#xff0c;开发环境…

数据库安全

先分3点从全局来看 对操作系统的安全需求:防止对DBMS的非法访问和修改,保护存储的数据、文件的安全性,对数据库用户的认证 对数据库系统本身的安全需求:用户认证管理、访问控制、审计,数据库的稳定性,保证数据的安全性与完整性&#xff0c;完善的恢复功能,数据加密 对数据库应用…

ST_LINK/V2 SWIM和SWD、JTAG下载口说明

LED状态说明 闪烁红色&#xff1a;ST-LINK/V2连接到计算机后&#xff0c;第一次USB枚举过程红色&#xff1a;ST-LINK/V2与计算机已建立连接闪烁绿色/红色&#xff1a;目标板和计算机在进行数据交换绿色&#xff1a;通讯完成橙色&#xff08;红色绿色&#xff09;&#xff1a;通…

js 日期扩展

// 对Date的扩展&#xff0c;将 Date 转化为指定格式的String // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符&#xff0c; // 年(y)可以用 1-4 个占位符&#xff0c;毫秒(S)只能用 1 个占位符(是 1-3 位的数字) // 例子&#xff1a; // (new Date()…

Gerrit的用法及与gitlab的区别

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 来到一个新的团队&#xff0c;开发的代码被同事覆盖了。找同事核实&#xff0c;同事却说根本没有看到我的代码。经过一番沟通…

人事资料

考察人品 1&#xff0e; 你有缺点吗 2&#xff0e; 当你发现你的顶头上司用办公电话聊私事&#xff0c;你会怎么做 3&#xff0e; 作为财务经理&#xff0c;如果总经理要求你在一年之内逃税100万&#xff0c;你会怎么做 4&#xff0e; 你的耳环多少钱买的 考察能力 1&#…

c语言位段

通常计算机最小处理单元基本就是byte字节了&#xff0c;就是八个二进制位&#xff0c;位段则是按计算机中真正的最小单位二进制位来存储处理数据&#xff0c;可以更高效的利用内存。 位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构…

The 15th UESTC Programming Contest Preliminary H - Hesty Str1ng cdoj1551

地址&#xff1a;http://acm.uestc.edu.cn/#/problem/show/1551 题目&#xff1a; Hesty Str1ng Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) A chrysanthemum was painted on the second page, and we tried to use the magic pow…

python基础之序列类型的方法——列表元组

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 Hello大家好&#xff0c;我是python学习者小杨同学&#xff0c;上次跟大家分享关于python的数值类型和序列类型&#xff0c;…

北方网-ios预科班

http://www.tudou.com/listplay/9oNp8KgmJZw.html 转载于:https://www.cnblogs.com/freeliver54/archive/2012/09/16/2687189.html

管家婆SQL SERVER数据库“可能发生了架构损坏。请运行DBCC CHECKCATALOG”修复

【数据库故障描述】用户在使用过过程中&#xff0c;由于突然断电&#xff0c;造成数据无法读取。DBCC检测数据库提示以下错误消息211&#xff0c;级别23&#xff0c;状态51&#xff0c;第1 行可能发生了架构损坏。请运行DBCC CHECKCATALOG。消息0&#xff0c;级别20&#xff0c…

1009 产生数 2002年NOIP全国联赛普及组

009 产生数 2002年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description给出一个整数 n&#xff08;n<10^30) 和 k 个变换规则&#xff08;k<15&#xff09;。  规则&#xff1a;   一位数可变换成另一个一位数&#…

K近邻算法

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 一、K近邻算法简介 K近邻算法(K-Nearest Neighbor)简称KNN算法,是最简单的预测模型之一&#xff0c;它没有多少数学上的假设…

easyui 点滴记录

为什么80%的码农都做不了架构师&#xff1f;>>> 【1.安装】&#xff1a;pip install easygui 【2.常用】 integerbox 交互式输入数字textbox 交互式输入文本ccbox 确认判断boolbox 是否判断multchoicebox 多选条目choicebox 单选条目buttonbox 单选按钮【3.体验一…

如何在邮件系统中使用自己的域名?

如何在邮件系统中使用自己的域名&#xff1f; 主要分为以下两种情况&#xff1a;1.MX记录已经存在&#xff1a; 如果MX记录已经存在&#xff0c;并且已经检查出是在某一个域名服务器上&#xff0c;您需要做的工作就是与您的域名服务商或该域名服务器的管理人员联系&#xff0c;…

IAR切BANK--BANK说明

一、为什么要用到BANK&#xff1f; C51单片机的最大寻址范围为2^1664K&#xff0c;为了突破64K代码的限制&#xff0c;就需要采用C51的切BANK。 二、切BANK的原理 代码地址空间的上半部 ,以重叠BANK0的物理地址空间 , 硬件设计了 n个存储 器页面来存储程序代码 。在任一时刻 …