异步编程相关的APM、Lambda、CCR、AsyncEnumerator(CLR)
2011-12-19 17:43 木木子 阅读(503) 评论(0) 编辑 收藏 举报传统异步编程操作
.NET平台的异步编程方式是APM(Asynchronous Programing Model,异步编程模式)。就是常见的BeginOperation和EndOperation二段式调用,并使用回调函数(AsyncCallback)和异步状态(IAsyncResult)。简单例子:
FileStream fs = new FileStream(@"C:\Data.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous);Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, result =>{int byteRead = fs.EndRead(result);
Process(data);fs.Close();}, null);
上述代码就是简单的使用了APM。有不足之处,就是需要显示的调用fs.close()方法,而不能使用using。例子中还使用了Lambda,使用Lambda的好处在于,能够访问到外部方法的局部变量。
传统操作的不利
APM使用两段式来实现异步操作,这样使得不能使用using、try…catch…finally。更不好的是,我要是两件有前后顺序的操作要异步执行,那代码会变的怎么样:
FileStream fs = new FileStream(@"C:\Data.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous);Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, readResult =>{int byteRead = fs.EndRead(readResult);
fs.BeginWrite(data, 0, data.Length, writeResult=>{fs.EndWrite(writeResult);Process(data);}, null);
Process(data);fs.Close();}, null);
两个异步操作相互嵌套,看起来真的很累啊。假如这种有前后顺序的操作更多呢,这将是一段恐怖的代码。
CCR
CCR中用到了基于迭代器(Iterator)的异步开发方式。使用yield关键字,很好的解决了这种有顺序的异步操作。看个例子:
static IEnumerable<int> ApmPatternWithIterator(){using (FileStream fs = new FileStream(@"C:\kbdlyot.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 8192, FileOptions.Asynchronous)){Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, readResult =>{int byteRead = fs.EndRead(readResult);
Process(data);}, null);
yield return 1;fs.BeginWrite(data, 0, data.Length, writeResult =>{fs.EndWrite(writeResult);Process(data);}, null);
yield return 1;}}上述的异步执行,不仅省去了相互嵌套的复杂,还能够使用using之类的关键字。
AsyncEnumerator
AsyncEnumerator是Jeffrey开发的,在Wintellect's .NET Power Threading Library中。AsyncEnumerator在功能上比CCR更完善。
用AsyncEnumerator修改上面的例子:
static IEnumerable<int> ApmPatternWithAsyncEnumerator(AsyncEnumerator enumerator){using (FileStream fs = new FileStream(@"C:\kbdlyot.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 8192, FileOptions.Asynchronous)){Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, enumerator.End(), null);
yield return 1;var res = fs.EndRead(enumerator.DequeueAsyncResult());fs.BeginWrite(data, 0, data.Length, enumerator.End(), null);
yield return 1;Process(data);}}