zoukankan      html  css  js  c++  java
  • DotNet中异步编程(APM)的研究2三种聚集方式rendevousing

    DotNet中异步编程(APM)的研究2
    三种聚集方式rendevousing (by zguosir/gshzheng)
    这个名字挺拗口,其实就是如何知道异步操作结束

    异步操作结束后,CLR将自动地

    l           设置IAsyncResult对象的IsCompleteTrue

    l           IAsyncResultAsyncWaitHandled对象设上信号;

    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())方法,调用线程挂起进入了休眠状态,等待操作完成。在实际应用中,如果在BeginReadEndRead之间放入一些代码,或者对这两个函数的调用分配在不用的方法调用中,就会体现APM的价值了。

     

    这两种方法的区别就是Example2中将等待与结束异步操作分离开了

     

     

    2.轮询polling

    使用轮询技巧,程序在开启异步操作后不需要等待其执行完毕,而可以干其它的事情。当在某次检查IAsyncResultIsComplete属性为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();

         }

    }

  • 相关阅读:
    java表达式中运算符优先级
    数据库建表规则
    linux 安装java环境
    springboot指定端口的三种方式
    服务器监控
    Dubbo 的配置主要分为三大类
    oracle数值函数 abs()、 ceil()、 cos()、 cosh()
    linux基础命令总结
    redis+sentinel集群部署
    centos7制作本地yum源
  • 原文地址:https://www.cnblogs.com/zguosir/p/877296.html
Copyright © 2011-2022 走看看