- 浏览: 145700 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
老八牛:
利用迭代器让异步操作更加“人性化”-山寨版的AsyncEnumerator -
老八牛:
为什么看不到代码?
利用迭代器让异步操作更加“人性化”-山寨版的AsyncEnumerator -
xi4nyu:
如果启动Application中的settings 的debu ...
玩蛇记-使用Tornado构建高性能Web之二-autoreload -
huacnlee:
"且在python下工作多日才发现原来在.NET下的 ...
玩蛇记-使用tornado构建高性能Web应用之一 -
jasongreen:
异步数据库操作,在web上有什么作用吗?
玩蛇记-使用tornado构建高性能Web应用之一
在msdn上读到 使用 AsyncEnumerator 简化 APM 一文,深感启发,但是找寻power threading库的源代码未果,遂山寨之,简陋不周之处多多包涵。
.NET下通过AsyncCallback回调来实现异步访问IO,比如FileStream,NetworkStream,之类的都有BeginXXX,和EndXXX等成对出现的方法,将实现AsyncCallback回调的方法作为参数传递给BeginXXX方法,在AsyncCallback回调的方法中调用EndXXX方法来结束一次异步回调。这是异步操作的一般模式。
先看一段同步的读取文件的方法:
为了使异步模式更加容易理解,我们需要把分开地方法合并起来。前文利用迭代器在.NET中实现“超轻量级线程” 中我提到了迭代器的效果是把一个方法拆分成了多个方法,那么这里我们反过来,把多个方法合并成一个方法,其实也可以使用迭代器。但是由于异步模式是在多线程下工作的,所以我们不能使用foreach来驱动迭代器,所以就需要一个AsyncEnumerator的类,由于找不到Power Threading的源码,所以我们自己来山寨一个出来。
我们先来看使用了AsyncEnumerator来驱动的异步读取文件的代码:
这段代码看起来就和同步读取时的逻辑差不多了,在一个方法内部,我们也可以使用using结构来确保回收资源。我们看到在beginread的时候使用了AsyncEnumerator的EndAction方法作为回调的方法,这个方法内部其实就是调用Enumerator对象的MoveNext方法,那么之后就会继续执行yield return 下边的代码。这里由于我们做了简化,一个AsyncEnumerator只能handle一个stream的一步操作,所以这里yield return 返回任意值都无所谓,由于EndXXX方法需要当前一步操作的结果对象一个IAsyncResult的对象作为参数,所以在AsyncEnumerator中有一个当前结果的属性,而在每一次EndAction的时候则用当前的结果对象更新之。遂得到AsyncEnumerator的内容为:
最后我们用他来读取一个文件:
.NET下通过AsyncCallback回调来实现异步访问IO,比如FileStream,NetworkStream,之类的都有BeginXXX,和EndXXX等成对出现的方法,将实现AsyncCallback回调的方法作为参数传递给BeginXXX方法,在AsyncCallback回调的方法中调用EndXXX方法来结束一次异步回调。这是异步操作的一般模式。
先看一段同步的读取文件的方法:
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 byte[] buffer = new byte[SegmentLength];
2 int readcount = 0;
3 int readtotal = 0;
4 while (true)
5 {
6 readcount = IOStream.Read(buffer, 0, SegmentLength);
7 readtotal += readcount;
8 yield return buffer;
9 if (readtotal >= Length)
10 {
11 break;
12 }
13 }
如果改成异步的方式,这个方法就要被拆分成两个方法,由于一次read只能读取一段,那么还需要额外的同步读取进度的对象,比如int rc,long total,byte[] buffer之类的具备变量就需要升格成为类变量。而读取的逻辑也由于方法被拆分而变得很难理解,代码如下:<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 byte[] buffer = new byte[SegmentLength];
2 int readcount = 0;
3 int readtotal = 0;
4 while (true)
5 {
6 readcount = IOStream.Read(buffer, 0, SegmentLength);
7 readtotal += readcount;
8 yield return buffer;
9 if (readtotal >= Length)
10 {
11 break;
12 }
13 }
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 int rc;
2 long total;
3 byte[] buffer = new byte[1024];
4 FileStream fs;
5 long length;
6 MemoryStream ms = new MemoryStream();
7 public void ReadFile(string FileName)
8 {
9 fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
10 length = fs.Length;
11 fs.BeginRead(buffer, 0, 1024, EndRead, null);
12 }
13 public void EndRead(IAsyncResult Ar)
14 {
15 rc = fs.EndRead(Ar);
16 total += rc;
17 ms.Write(buffer, 0, rc);
18 if (total < length)
19 {
20 fs.BeginRead(buffer, 0, 1024, EndRead, null);
21 }
22 }
我们可以看到这样子的代码很晦涩,且IO类的资源回收成了一个问题,在同步的模式下在一个方法里只需要使用using结构就不用担心IO的资源回收,这里我们就需要外部的类实现IDisposable接口来保证对IO资源的回收。<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 int rc;
2 long total;
3 byte[] buffer = new byte[1024];
4 FileStream fs;
5 long length;
6 MemoryStream ms = new MemoryStream();
7 public void ReadFile(string FileName)
8 {
9 fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
10 length = fs.Length;
11 fs.BeginRead(buffer, 0, 1024, EndRead, null);
12 }
13 public void EndRead(IAsyncResult Ar)
14 {
15 rc = fs.EndRead(Ar);
16 total += rc;
17 ms.Write(buffer, 0, rc);
18 if (total < length)
19 {
20 fs.BeginRead(buffer, 0, 1024, EndRead, null);
21 }
22 }
为了使异步模式更加容易理解,我们需要把分开地方法合并起来。前文利用迭代器在.NET中实现“超轻量级线程” 中我提到了迭代器的效果是把一个方法拆分成了多个方法,那么这里我们反过来,把多个方法合并成一个方法,其实也可以使用迭代器。但是由于异步模式是在多线程下工作的,所以我们不能使用foreach来驱动迭代器,所以就需要一个AsyncEnumerator的类,由于找不到Power Threading的源码,所以我们自己来山寨一个出来。
我们先来看使用了AsyncEnumerator来驱动的异步读取文件的代码:
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 IEnumerable ReadFile(AsyncEnumerator Ae, MemoryStream Data)
2 {
3 int rc = 0;
4 long total = 0;
5 FileInfo fi = new FileInfo(@"a file path XXXXXXX mask");
6 byte[] bf = new byte[1024];
7 using (FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
8 {
9 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
10 yield return 1;
11 while (true)
12 {
13 rc = fs.EndRead(Ae.CurrentAr);
14 total += rc;
15 Data.Write(bf, 0, rc);
16 if (total >= fi.Length)
17 {
18 fs.Close();
19 break;
20 }
21 else
22 {
23 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
24 yield return 1;
25 }
26 }
27 yield break;
28 }
29 }
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 IEnumerable ReadFile(AsyncEnumerator Ae, MemoryStream Data)
2 {
3 int rc = 0;
4 long total = 0;
5 FileInfo fi = new FileInfo(@"a file path XXXXXXX mask");
6 byte[] bf = new byte[1024];
7 using (FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
8 {
9 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
10 yield return 1;
11 while (true)
12 {
13 rc = fs.EndRead(Ae.CurrentAr);
14 total += rc;
15 Data.Write(bf, 0, rc);
16 if (total >= fi.Length)
17 {
18 fs.Close();
19 break;
20 }
21 else
22 {
23 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
24 yield return 1;
25 }
26 }
27 yield break;
28 }
29 }
这段代码看起来就和同步读取时的逻辑差不多了,在一个方法内部,我们也可以使用using结构来确保回收资源。我们看到在beginread的时候使用了AsyncEnumerator的EndAction方法作为回调的方法,这个方法内部其实就是调用Enumerator对象的MoveNext方法,那么之后就会继续执行yield return 下边的代码。这里由于我们做了简化,一个AsyncEnumerator只能handle一个stream的一步操作,所以这里yield return 返回任意值都无所谓,由于EndXXX方法需要当前一步操作的结果对象一个IAsyncResult的对象作为参数,所以在AsyncEnumerator中有一个当前结果的属性,而在每一次EndAction的时候则用当前的结果对象更新之。遂得到AsyncEnumerator的内容为:
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class AsyncEnumerator
2 {
3 AsyncCallback end;
4
5 public IAsyncResult CurrentAr
6 {
7 get;
8 set;
9 }
10
11 public void EndAction(IAsyncResult Ar)
12 {
13 CurrentAr = Ar;
14 if (!enumerator.MoveNext())
15 {
16
17 }
18 }
19
20 }
但是这个时候我们无法开始整个迭代的过程,所以我们需要给AsyncEnumerator增加一个开始迭代的方法,同时,完成后也需要一个通知,所以开始迭代的方法里要增加一个回调方法的委托作为参数,由于在这个方法里驱动Enumerator的迭代所以也需要把IEnumerator的对象也传进去。最后得到完整的AsyncEnumerator的代码为:<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class AsyncEnumerator
2 {
3 AsyncCallback end;
4
5 public IAsyncResult CurrentAr
6 {
7 get;
8 set;
9 }
10
11 public void EndAction(IAsyncResult Ar)
12 {
13 CurrentAr = Ar;
14 if (!enumerator.MoveNext())
15 {
16
17 }
18 }
19
20 }
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class AsyncEnumerator
2 {
3 IEnumerator enumerator;
4 AsyncCallback end;
5
6 public IAsyncResult CurrentAr
7 {
8 get;
9 set;
10 }
11
12 public void EndAction(IAsyncResult Ar)
13 {
14 CurrentAr = Ar;
15 if (!enumerator.MoveNext())
16 {
17 end(Ar);
18 }
19 }
20 public void Start(IEnumerator Enumerator, AsyncCallback End)
21 {
22 enumerator = Enumerator;
23 if (enumerator.MoveNext())
24 {
25 end = End;
26 }
27 }
28
29 }
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class AsyncEnumerator
2 {
3 IEnumerator enumerator;
4 AsyncCallback end;
5
6 public IAsyncResult CurrentAr
7 {
8 get;
9 set;
10 }
11
12 public void EndAction(IAsyncResult Ar)
13 {
14 CurrentAr = Ar;
15 if (!enumerator.MoveNext())
16 {
17 end(Ar);
18 }
19 }
20 public void Start(IEnumerator Enumerator, AsyncCallback End)
21 {
22 enumerator = Enumerator;
23 if (enumerator.MoveNext())
24 {
25 end = End;
26 }
27 }
28
29 }
最后我们用他来读取一个文件:
Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class Program
2 {
3 static MemoryStream data = new MemoryStream();
4
5 static void Main(string[] args)
6 {
7 AsyncEnumerator Ae = new AsyncEnumerator();
8 IEnumerator ie = ReadFile(Ae, data).GetEnumerator();
9 Ae.Start(ie, End);
10 Console.Read();
11 }
12
13 static void End(IAsyncResult Ar)
14 {
15 string txt = Encoding.UTF8.GetString(data.ToArray());
16 Console.WriteLine(txt);
17 }
18
19 static IEnumerable ReadFile(AsyncEnumerator Ae, MemoryStream Data)
20 {
21 int rc = 0;
22 long total = 0;
23 FileInfo fi = new FileInfo(@"SOME FILE PATH XXXXXX");
24 byte[] bf = new byte[1024];
25 using (FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
26 {
27 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
28 yield return 1;
29 while (true)
30 {
31 rc = fs.EndRead(Ae.CurrentAr);
32 total += rc;
33 Data.Write(bf, 0, rc);
34 if (total >= fi.Length)
35 {
36 fs.Close();
37 break;
38 }
39 else
40 {
41 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
42 yield return 1;
43 }
44 }
45 yield break;
46 }
47 }
48
49 }
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 1 class Program
2 {
3 static MemoryStream data = new MemoryStream();
4
5 static void Main(string[] args)
6 {
7 AsyncEnumerator Ae = new AsyncEnumerator();
8 IEnumerator ie = ReadFile(Ae, data).GetEnumerator();
9 Ae.Start(ie, End);
10 Console.Read();
11 }
12
13 static void End(IAsyncResult Ar)
14 {
15 string txt = Encoding.UTF8.GetString(data.ToArray());
16 Console.WriteLine(txt);
17 }
18
19 static IEnumerable ReadFile(AsyncEnumerator Ae, MemoryStream Data)
20 {
21 int rc = 0;
22 long total = 0;
23 FileInfo fi = new FileInfo(@"SOME FILE PATH XXXXXX");
24 byte[] bf = new byte[1024];
25 using (FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
26 {
27 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
28 yield return 1;
29 while (true)
30 {
31 rc = fs.EndRead(Ae.CurrentAr);
32 total += rc;
33 Data.Write(bf, 0, rc);
34 if (total >= fi.Length)
35 {
36 fs.Close();
37 break;
38 }
39 else
40 {
41 fs.BeginRead(bf, 0, 1024, Ae.EndAction, null);
42 yield return 1;
43 }
44 }
45 yield break;
46 }
47 }
48
49 }
发表评论
-
关于ORM和内存数据库的遐想
2007-01-23 13:21 570最近有消息说韩国电信 ... -
继续ORM-欧德巴赫猜想-Mapping
2007-01-23 14:34 666最近从项目组单离出来开始在公司实施过程化管理,整个QA Off ... -
剑走偏锋,小心走火入魔
2007-01-23 15:07 706这是很久前写好的文字,闲得无聊就发上来,几个月前的感想,上午一 ... -
手把手教你写ORM(三)
2007-01-24 11:50 605昨天处于晕死状态,少写了一个组件,还需要一个组件用来专门管理C ... -
手把手教你写ORM(四)
2007-01-24 13:51 641现在中午不睡一会儿就头晕。前一篇有人留言说为什么不写web.c ... -
手把手教你写ORM(五)
2007-01-24 15:29 604CMMI是魔鬼继续上面的内容,这里我们要实现一个插件的结构来动 ... -
谈谈我们的学习和我们的Blog
2007-01-24 20:07 407第一,学习编程是一个很枯燥的过程,所以我们更要讲究效率(要把有 ... -
手把手教你写代码生成器(也算ORM的续)
2007-01-25 11:45 724因为ORM还是需要配置,还是需要EntityObject,所以 ... -
粒度细到控件的权限管理系统的设计(概要篇)
2007-01-25 21:40 1066其实这个设计是已经做过了,那个时候我才进公司还在试用期,给我的 ... -
粒度细到控件的权限管理组件(构想篇)
2007-01-26 10:34 747说老实话我现在还没开 ... -
手把手教你写ORM大全篇
2007-01-26 19:36 680根据dudu boss的建议将本系列作一个归纳,下一个系列正在 ... -
架构设计的非侵入性原则
2007-01-27 00:41 698最近常常看到JAVA社区热 ... -
手把手教你可复用SSO组件的设计(原理篇)
2007-01-27 14:55 758在结构设计上复用性 ... -
对《万事欠备设计先行》的一点想法,兼谈XP和CMMI
2007-01-29 09:31 650周末陪女友,故沉默了,其实大脑并没有沉默,之前看到《万事欠备设 ... -
手把手教你可复用的SSO组件设计(设计篇)
2007-01-29 16:24 592周末陪女朋友去了,没写,告罪,上班后急忙补上。 这里说到了可复 ... -
手把手教你可复用的SSO组件设计(实现篇)
2007-01-29 22:30 609费了一夜的功夫写完这些代码,有些凌乱,望见谅。 首先是对加密解 ... -
玩具级嵌入式内存对象数据库^V^
2007-02-01 19:46 495纯粹是为了好玩:} 最近几天很忙所以写得少了,昨天在清理硬盘的 ... -
差之毫厘谬以千里-计算中的精度问题
2007-02-27 10:04 586如果你只是i++来作计数 ... -
动态语言,涅磐重生还是死路一条?
2007-03-06 10:31 580最近花时间一直在看python和ruby,为了在Web应用又看 ... -
ASP.NET's MVC is what a joke!
2007-03-08 13:43 477很早前还在毁人不倦的 ...
相关推荐
`each-async`库正是利用这一特性,提供了异步迭代器,允许我们处理数组或对象的每个元素时执行异步操作。 2. **回调函数**:`each-async`的使用方式与`forEach`类似,需要传递一个回调函数,该函数将在每个元素上...
双向迭代器是一种具有前向迭代器的全部功能的迭代器,另外它还可以利用自减操作符 operator-- 向后移动一个位置。由 list 容器中返回的迭代器都是双向的。 5. 随机访问迭代器(Random Access Iterator) 随机访问...
C++ STL中迭代器介绍 迭代器 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定...
为了更好地利用迭代器,STL提供了`std::iterator_traits`,这是一个模板类,用于获取迭代器的类型信息。例如: - `std::iterator_traits<Iterator>::value_type` 表示迭代器所指向的类型。 - `std::iterator_traits...
在Java编程语言中,迭代器模式...这种灵活性和封装性是迭代器模式的主要优点,使程序设计更加模块化和可扩展。在实际应用中,这种模式可以广泛应用于各种需要遍历集合的场景,如数据处理、图形用户界面元素的遍历等。
在C++编程语言中,迭代器(Iterator)是STL(Standard Template Library,标准模板库)的核心组件之一,它提供了一种访问容器中元素的方法,类似于指针,但功能更加强大和灵活。迭代器提供了统一的接口,使得开发者...
- **初始化**:通常使用容器成员函数`begin()`获取指向容器第一个元素的迭代器,使用`end()`获取指向容器最后一个元素后一个位置的迭代器。 - **解引用**:使用`*`运算符获取迭代器所指向的元素。 - **递增/递减**:...
同时,Java 8引入的流(Stream)API也提供了类似迭代器的功能,但更加强大且易于链式操作。 综上所述,迭代器模式是一种实用的设计模式,它在Java编程中起着核心作用,帮助开发者有效地遍历和操作聚合数据。极客...
然而,迭代器并不是无条件安全的,某些操作会导致迭代器失效,这可能是程序运行时出现未定义行为的根源。以下是对C++中迭代器失效问题的详细分析: 1. **插入和删除操作**:在容器中进行插入或删除元素时,迭代器...
用迭代器输出向量和普通输出,Iterator str=vs.iterator()
根据提供的文件信息,我们可以深入探讨迭代器(Iterator)这一设计模式在Java中的应用与实现...通过学习并理解迭代器模式的原理及其实现方式,开发者可以在实际项目中更好地利用这一模式来优化代码结构,提高程序性能。
1. **迭代器接口**:定义了迭代器的基本操作,例如`first()`用于移到聚合对象的第一个元素,`next()`用于移到下一个元素,`isDone()`用于检查是否已经遍历完所有元素,`currentItem()`用于获取当前元素。 2. **聚合...
输入迭代器(Input Iterator)、输出迭代器(Output Iterator)、前向迭代器(Forward Iterator)、双向迭代器(Bidirectional Iterator)和随机访问迭代器(Random Access Iterator),它们各自支持不同的操作。...
迭代器模式使得客户代码可以独立于具体的聚合类进行迭代操作,提高了代码的可复用性和灵活性。 ### 2. 结构组成 迭代器模式包含以下角色: - **抽象迭代器(Iterator)**:定义了遍历元素的接口,包括初始化、判断...
在这个主题中,我们主要探讨了如何利用组合模式(Composite Pattern)构建二叉树,并通过迭代器模式(Iterator Pattern)来实现对树的遍历,包括前序、中序和后序遍历。这些是设计模式中的经典应用,对于理解和掌握...
前向迭代器结合了输入迭代器和输出迭代器的功能,不仅支持读写操作,还允许向前推进迭代器至序列中的下一个元素。它们支持所有输入迭代器的操作,并增加了后缀递增操作(`++`)。然而,它们不支持递减操作,因此不能...
生成器与迭代器的Objective-C实现,实现类似ES6/Python的yield语意,async异步块,支持在Objective-C/Swift项目中以同步风格编写异步代码,避免长回调链和Promise链.
- **文件处理**:处理文件时,可能需要遍历文件的每一行或每一个记录,迭代器模式可以使得这种遍历更加方便和直观。 - **网络协议**:在分析或处理网络数据包时,使用迭代器模式可以方便地遍历数据包的不同部分。 #...