三种聚集方式rendevousing (by zguosir/gshzheng)
这个名字挺拗口,其实就是如何知道异步操作结束
异步操作结束后,CLR将自动地
l 设置IAsyncResult对象的IsComplete为True;
l 为IAsyncResult的AsyncWaitHandled对象设上信号;
l 如果设置了回调函数,则调用它。
程序有三种方式可以获知异步操作是否已经执行完成,我们称之为聚集技巧(Rendezvous Techniques)。等待直到完成(wait-until-done)、轮询(polling)和回调方法(callback)。选择哪一个依赖于程序是否有当异步操作执行完毕后要执行的指令。(实际中,最常用的是回调方法)
1.等待直到完成
调用线程启动一个异步操作后将被挂起,直到异步操作结束。在这种方式下,所谓的异步操作从执行效果上看就相当于其对应的同步操作了。有两种方式可以挂起当前调用线程,等待异步操作的完成。
l 直接调用EndOperation()方法,等待执行结果;
l 使用IAsyncResult对象AsnycWaitHandle.WaitOne()方法来等待。
下面的例子演示了用第一种方式通过异步操作从读取文件内容:
Example1
public class WaitUntilDone0
{
public static void ReadFileAsync()
{
//打开文件并指定异步操作
FileStream
fs=new
FileStream(@"c:\apm.txt",FileMode.Open,
FileAccess.Read,FileShare.Read,1024,true);
//开启异步读取
byte[] data = new byte[100];
IAsyncResult
ar = fs.BeginRead(data,0,data.Length,null,null);
//执行某些代码...
try
{
//等待直到异步读取完成,并结束异步操作
int cnt = fs.EndRead(ar);
fs.Close();
Console.WriteLine(BitConverter.ToString(data,0,cnt));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
下面的例子演示了第二种方式,利用异步操作从读取文件内容:
Example2
…
//开启异步读取
byte[] data = new byte[100];
IAsyncResult ar = fs.BeginRead(data,0,data.Length,null,null);
//执行某些代码...
//等待直到异步读取完成
ar.AsyncWaitHandle.WaitOne();
try
{
//结束异步操作,并得到结果
int cnt = fs.EndRead(ar);
fs.Close();
}
…
上面两个程序并没有有效的利用APM,因为在BeginRead()之后,我们就立即调用了EndRead()(或WaitOne())方法,调用线程挂起进入了休眠状态,等待操作完成。在实际应用中,如果在BeginRead和EndRead之间放入一些代码,或者对这两个函数的调用分配在不用的方法调用中,就会体现APM的价值了。
这两种方法的区别就是Example2中将等待与结束异步操作分离开了
2.轮询polling
使用轮询技巧,程序在开启异步操作后不需要等待其执行完毕,而可以干其它的事情。当在某次检查IAsyncResult的IsComplete属性为true时,即可知道操作已完成,调用EndOperation()得到其结果。Example3是用轮询技巧来完成异步读文件的功能:
Example3
…
//开启异步读取
byte[] data = new byte[100];
IAsyncResult ar = fs.BeginRead(data,0,data.Length,null,null);
//执行某些代码...
//不停查询异步操作执行的状态,直到执行完毕
while(!ar.IsCompleted)
{
//刷新用户界面
Console.Write(".");
Thread.Sleep(10);
}
Console.WriteLine();
try
{
//结束异步操作,并得到结果
int cnt = fs.EndRead(ar);
fs.Close();
}
…
本例中,为了简单的目的,直接在调用了BeginRead()后,就开始循环查询了,实际编写使用轮询技巧的代码时,一般是让单独的线程定期地来查询异步操作是否结束。
3.回调callback
在构建高性能和可扩展的应用程序架构时,回调方法是最好用的聚集技巧。它在任何时候都不用将调用线程挂起等待,也不会需要另外的不定期的检查操作是否完成。
回调方法是一个符合AsyncCallBack签名的方法,在调用开启异步操作时,将回调方法传入BeginOperation()。当异步操作执行完毕后,将自动调用这个方法,在这个方法中调用EndOperation()得到执行的结果。
Example4
public class Callback
{
//在class-scope定义缓冲区
private static byte[] data=null;
public static void cb_read(IAsyncResult ar)
{
FileStream
fs= ar.AsyncState as FileStream;
try
{
//结束异步操作,并得到结果
int cnt = fs.EndRead(ar);
fs.Close();
Console.WriteLine(BitConverter.ToString(data,0,cnt));
}
catch(Exception e)
{
Console.WriteLine("An
exception occurred while processing :{0}",e.Message);
}
}
public static void ReadFileAsync()
{
//打开文件并指定异步操作
FileStream
fs=new
FileStream(@"c:\apm.txt",FileMode.Open,
FileAccess.Read,FileShare.Read,1024,true);
//开启异步读取
data = new byte[100];
IAsyncResult
ar = fs.BeginRead(data,0,data.Length,new
AsyncCallback(cb_read),fs);
//执行某些代码...
Console.ReadLine();
}
}