8天玩转并行开发——第六天 异步编程模型

在.net里面异步编程模型由来已久,相信大家也知道Begin/End异步模式和事件异步模式,在task出现以后,这些东西都可以被task包装

起来,可能有人会问,这样做有什么好处,下面一一道来。

一: Begin/End模式

1: 委托

在执行委托方法的时候,我们常常会看到一个Invoke,同时也有一对你或许不常使用的BeginInvoke,EndInvoke方法对,当然Invoke方法

是阻塞主线程,而BeginInvoke则是另开一个线程。

 1     class Program
 2     {
 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 Program
 2     {
 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 Program
 2     {
 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 Program
 2     {
 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/Jeely/p/10999355.html

时间: 2024-07-28 19:40:51

8天玩转并行开发——第六天 异步编程模型的相关文章

8天玩转并行开发——第七天 简要分析任务与线程池

原文:8天玩转并行开发--第七天 简要分析任务与线程池 其实说到上一篇,我们要说的task的知识也说的差不多了,这一篇我们开始站在理论上了解下“线程池”和“任务”之间的关系,不管是 说线程还是任务,我们都不可避免的要讨论下线程池,然而在.net 4.0以后,线程池引擎考虑了未来的扩展性,已经充分利用多核微处理器 架构,只要在可能的情况下,我们应该尽量使用task,而不是线程池. 首先看一下task的结构 从图中我们可以看出Task.Factory.StartNew()貌似等同于用ThreadPo

8天玩转并行开发——第八天 用VS性能向导解剖你的程序

原文:8天玩转并行开发--第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需要 用到”性能向导“,通过性能报告便于我们快速的发现并找到潜在的性能问题. 首先我们上一段需要改进的代码: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using

Win8.1应用开发之异步编程

在win8应用商店开发时,我们会遇到许多异步方法,它们存在的目的就是为了确保你的应用在执行需要大量时间的任务时仍能保持良好的响应,也就是说调用异步API是为了响应用户的操作.设想一下我们点击一个Button,会从网上下载一些信息,如果没有异步,我们就不得不等它下载完才能继续进行操作.为了能在下载时保持响应,windows提供了一个用于下载源的异步方法SyndicationClient.RetrieveFeedAsync. // Put the keyword, async on the decl

.NET &ldquo;底层&rdquo;异步编程模式&mdash;&mdash;异步编程模型

本文内容 异步编程类型 环境 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Programming Model,APM),它们的中文翻译只差一个字,英文名称差在最后一个单词,看英文一个是 Pattern,一个是 Model.Model 比 Pattern 更具体.前者是一个统称,比后者含义要广,前者包含三个模型,而 APM 只是它其中一个而已. 个人理解,异步编程模型(APM

.net异步编程の-------异步编程模型(APM)

术语解释: APM               异步编程模型, Asynchronous Programming Model EAP                基于事件的异步编程模式, Event-based Asynchronous Pattern TAP                基于任务的异步编程模式, Task-based Asynchronous Pattern 一.异步编程 APM即异步编程模型的简写(Asynchronous Programming Model),大家在写代

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

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

简单地使用线程之一:使用异步编程模型

.NetFramework的异步编程模型从本质上来说是使用线程池来完成异步的任务,异步委托.HttpWebRequest等都使用了异步模型. 这里我们使用异步委托来说明异步编程模型. 首先,我们来明确一下,对于多线程来说,我们需要关注哪些问题. “线程是一段执行中的代码流”,从这句话中,我们可以关注这段代码流何时开始执行.何时结束.从主线程如何传递参数至从子线程.从子线程如何返回结果至主线程? 问题1:在异步编程模型中,子线程何时开始执行? 对于异步编程模型来说,使用BeginXXX来开始执行线

C#异步编程模型

什么是异步编程模型 异步编程模型(Asynchronous Programming Model,简称APM)是C#1.1支持的一种实现异步操作的编程模型,虽然已经比较"古老"了,但是依然可以学习一下的.通过对APM的学习,我总结了以下三点: 1. APM的本质是使用委托和线程池来实现异步编程的. 2. 实现APM的关键是要实现IAsyncResult接口. 3. 实现了APM的类都会定义一对形如BeginXXX()和EndXXX()的方法,例如,FileStream类定义了BeginR

异步编程模型(APM)

一.概念 APM即异步编程模式的简写(Asynchronous Programming Model).大家在写代码的时候或者查看.NET 的类库的时候肯定会经常看到和使用以BeginXXX和EndXXX类似的方法,其实你在使用这些方法的时候,你就再使用异步编程模型来编写程序.NET Framework很多类也实现了该模式,同时我们也可以自定义类来实现该模式,(也就是在自定义的类中实现返回类型为IAsyncResult接口的BeginXXX方法和EndXXX方法),另外委托类型也定义了BeginI