zoukankan      html  css  js  c++  java
  • 异步调用详解

    C#异步调用四大方法是什么呢?C#异步调用四大方法的使用是如何进行的呢?让我们首先了解下什么时候用到C#异步调用:

    .NET Framework
    允许您C#异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和
    EndInvoke 方法。

    BeginInvoke
    方法用于启动C#异步调用。它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。BeginInvoke
    立即返回,不等待C#异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。

    EndInvoke 方法用于检索C#异步调用结果。调用 BeginInvoke 后可随时调用
    EndInvoke 方法;如果C#异步调用未完成,EndInvoke 将一直阻塞到C#异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out
    和 ref 参数(在 Visual Basic 中为 ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

    注意:Visual Studio .NET 中的智能感知功能会显示 BeginInvoke 和
    EndInvoke 的参数。如果您没有使用 Visual Studio 或类似的工具,或者您使用的是 C# 和 Visual Studio
    .NET,请参见异步方法签名获取有关运行库为这些方法定义的参数的描述。
    一.C#异步调用四大方法详解

    本主题中的代码演示了四种使用
    BeginInvoke 和 EndInvoke 进行C#异步调用的常用方法。调用了 BeginInvoke 后,可以:

    · 进行某些操作,然后调用 EndInvoke
    一直阻塞到调用完成。

    · 使用
    IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle
    信号,然后调用 EndInvoke。

    · 轮询由 BeginInvoke 返回的
    IAsyncResult,确定C#异步调用何时完成,然后调用 EndInvoke。

    · 将用于回调方法的委托传递给
    BeginInvoke。该方法在C#异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。

    警告:始终在C#异步调用完成后调用 EndInvoke。

    测试方法和异步委托

    四个示例全部使用同一个长期运行的测试方法
    TestMethod。该方法显示一个表明它已开始处理的控制台信息,休眠几秒钟,然后结束。TestMethod 有一个 out 参数(在 Visual Basic
    中为 ByRef),它演示了如何将这些参数添加到 BeginInvoke 和 EndInvoke 的签名中。您可以用类似的方式处理 ref 参数(在
    Visual Basic 中为 ByRef)。

    下面的代码示例显示 TestMethod 以及代表 TestMethod
    的委托;若要使用任一示例,请将示例代码追加到这段代码中。

    注意 为了简化这些示例,TestMethod 在独立于 Main()
    的类中声明。或者,TestMethod 可以是包含 Main() 的同一类中的 static 方法(在 Visual Basic 中为 Shared)。

    using System;
    using System.Threading;
    public class AsyncDemo
    {
        // The method to be
        //executed asynchronously.
    
        public string TestMethod(int callDuration, out int threadId)
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = AppDomain.GetCurrentThreadId();
            return "MyCallTime was" + callDuration.ToString();
         }
    }
    // The delegate must have
    //the same signature as the method
    // you want to call asynchronously.
    public delegate string AsyncDelegate(int callDuration, out int threadId);

    0x01:C#异步调用四大方法之使用
    EndInvoke 等待异步调用

    异步执行方法的最简单方式是以 BeginInvoke 开始,对主线程执行一些操作,然后调用
    EndInvoke。EndInvoke 直到C#异步调用完成后才返回。这种技术非常适合文件或网络操作,但是由于它阻塞
    EndInvoke,所以不要从用户界面的服务线程中使用它。

    public class AsyncMain
    {
        static void Main(string[] args)
        {
            // The asynchronous method
          //  puts the thread id here.
        int threadId;
    AsyncDemo ad = new AsyncDemo();
    
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
    
        IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null, null);
        Thread.Sleep(0);
    Console.WriteLine("Main thread{0} does some work.",
    AppDomain.GetCurrentThreadId());
    
    string ret = dlgt.EndInvoke(out threadId, ar);
        Console.WriteLine("The call executed on thread{0},with return value"{1}".",threadId, ret);
    }
    }

    0x02:C#异步调用四大方法之使用
    WaitHandle 等待异步调用

    等待 WaitHandle 是一项常用的线程同步技术。您可以使用由 BeginInvoke 返回的
    IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。C#异步调用完成时会发出 WaitHandle
    信号,而您可以通过调用它的 WaitOne 等待它。

    如果您使用 WaitHandle,则在C#异步调用完成之后,但在通过调用 EndInvoke
    检索结果之前,可以执行其他处理。

    public class AsyncMain
    {
        static void Main(string[] args)
        {
        int threadId;
        AsyncDemo ad = new AsyncDemo();
        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
        IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null);
        Thread.Sleep(0);
        Console.WriteLine("Main thread{0} does some work.",AppDomain.GetCurrentThreadId());
        string ret = dlgt.EndInvoke(out threadId, ar);
        Console.WriteLine("The call executed on thread{0},with return value"{1}".",threadId, ret);
        }
    }

    0x03:C#异步调用四大方法之轮询异步调用完成

    您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted
    属性来发现C#异步调用何时完成。从用户界面的服务线程中进行C#异步调用时可以执行此操作。轮询完成允许用户界面线程继续处理用户输入。

    public class AsyncMain
    {
        static void Main(string[] args)
        {
          int threadId;
      
           AsyncDemo ad = new AsyncDemo();
    
           AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
    
           IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null);
    
            while(ar.IsCompleted ==false) {
              Thread.Sleep(10);
            }
    
            string ret = dlgt.EndInvoke(out threadId, ar);
            Console.WriteLine("The call executed on thread{0},with return value"{1}".",threadId, ret);
        }
    }

    0x04:C#异步调用四大方法之异步调用完成时执行回调方法

    如果启动异步调用的线程不需要处理调用结果,则可以在调用完成时执行回调方法。回调方法在
    ThreadPool 线程上执行。

    要使用回调方法,必须将代表该方法的 AsyncCallback 委托传递给
    BeginInvoke。也可以传递包含回调方法将要使用的信息的对象。例如,可以传递启动调用时曾使用的委托,以便回调方法能够调用 EndInvoke。

    public class AsyncMain
    {
    
       private static int threadId;
       static void Main(string[] args)
        {
    
         AsyncDemo ad = new AsyncDemo();
         AsyncDelegate dlgt = new  AsyncDelegate(ad.TestMethod);
    
        IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId,new AsyncCallback(CallbackMethod),dlgt);
        Console.WriteLine("DIVss Enter to close application.");
        Console.ReadLine();
        }
      static void CallbackMethod(IAsyncResult ar)
     {
    
       AsyncDelegate dlgt = (AsyncDelegate)
    
       string ret = dlgt.EndInvoke(out threadId, ar);
        Console.WriteLine("The call executed on thread{ 0},with return value"{1}".",threadId, ret);
     }
    }

    二.C#异步调用四大方法的基本内容就向你介绍到这里,下面看有回调函数的WebRequestWebResponse的异步操作。

    using System;
    using System.Net;
    using System.Threading;
    using System.Text;
    using System.IO;
    
    
    // RequestState 类用于通过
    // 异步调用传递数据
    public class RequestState
    {
        const int BUFFER_SIZE = 1024;
        public StringBuilder
        RequestData;
        public byte[]
        BufferRead;
        public HttpWebRequest
        Request;
        public Stream
        ResponseStream;
        // 创建适当编码类型的解码器
        public Decoder StreamDecode =
        Encoding.UTF8.GetDecoder();
    
        public
        RequestState()
        {
            BufferRead =
            new byte[BUFFER_SIZE];
            RequestData
            = new StringBuilder("");
            Request =
            null;
            ResponseStream
            = null;
        }
    }
    
    // ClientGetAsync 发出异步请求
    class ClientGetAsync
    {
        public static ManualResetEvent allDone =
        new ManualResetEvent(false);
        const int BUFFER_SIZE = 1024;
    
        public static void Main(string[] args)
        {
    
            if (args.Length < 1)
            {
                showusage();
                return;
            }
    
            // 从命令行获取 URI
            Uri
            HttpSite = new Uri(args[0]);
    
            // 创建请求对象
            HttpWebRequest
            wreq =
            (HttpWebRequest)WebRequest.Create(HttpSite);
    
            // 创建状态对象
            RequestState
            rs = new
            RequestState();
    
            // 将请求添加到状态,以便它可以被来回传递
            rs.Request
            = wreq;
    
            // 发出异步请求
            IAsyncResult
            r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(RespCallback),
            rs);
    
           allDone.WaitOne();
        }
    
        public static void showusage()
        {
            Console.WriteLine("尝试获取 (GET) 一个 URL");
            Console.WriteLine("
    用法::");
            Console.WriteLine("ClientGetAsync URL");
            Console.WriteLine("示例::");
            Console.WriteLine("ClientGetAsyn  http://www.microsoft.com/net/");
    }
    
        private static void RespCallback(IAsyncResult ar)
        {
            // 从异步结果获取 RequestState 对象
            RequestState
            rs =
            (RequestState)ar.AsyncState;
    
            // 从 RequestState 获取 HttpWebRequest
            HttpWebRequest req=rs.Request;
    
            // 调用 EndGetResponse 生成 HttpWebResponse 对象
            // 该对象来自上面发出的请求
            HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(ar);
    
            // 既然我们拥有了响应,就该从
            //响应流开始读取数据了
            Stream ResponseStream = resp.GetResponseStream();
            // 该读取操作也使用异步完成,所以我们
            //将要以 RequestState         存储流    
            rs.ResponseStream= ResponseStream;
    
            // 请注意,rs.BufferRead 被传入到 BeginRead。
            //
            //这是数据将被读入的位置。
           IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead,0, BUFFER_SIZE, new AsyncCallback(ReadCallBack),rs);
        }
    
    
        private static void ReadCallBack(IAsyncResult asyncResult)
        {
            // 从 asyncresult 获取 RequestState 对象
            RequestState rs =  (RequestState)asyncResult.AsyncState;
    
            // 取出在 RespCallback 中设置的 ResponseStream
            Stream responseStream = rs.ResponseStream;
    
            // 此时 rs.BufferRead 中应该有一些数据。
            //读取操作将告诉我们那里是否有数据
            int read =responseStream.EndRead(asyncResult);
    
            if (read > 0)
            {
                // 准备 Char 数组缓冲区,用于向 Unicode 转换
                Char[]
                charBuffer = new
                Char[BUFFER_SIZE];
    
                // 将字节流转换为 Char 数组,然后转换为字符串
                //len 显示多少字符被转换为Unicode
               int len =rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);
                String str = new String(charBuffer, 0, len);
    
                // 将最近读取的数据追加到 RequestData stringbuilder 对象中,
                //该对象包含在 RequestState中
               rs.RequestData.Append(str);
    
    
                // 现在发出另一个异步调用,读取更多的数据
                // 请注意,将不断调用此过程,直到
            //responseStream.EndRead 返回-1
            IAsyncResult ar = responseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
            }
            else
            {
                if (rs.RequestData.Length >
                1)
                {
                    // 所有数据都已被读取,因此将其显示到控制台
                    string
                    strContent;
                    strContent
                    =
                    rs.RequestData.ToString();
                    Console.WriteLine(strContent);
                }
    
                // 关闭响应流
                responseStream.Close();
    
                // 设置 ManualResetEvent,以便主线程可以退出
                allDone.Set();
            }
            return;
        }
    }

    在这里有回调函数,且异步回调中又有异步操作。

    首先是异步获得ResponseStream,然后异步读取数据。

    这个程序非常经典。从中可以学到很多东西的。我们来共同探讨。

    总结

    上面说过,.net framework 可以异步调用任何方法。所以异步用处广泛。

    在.net framework 类库中也有很多异步调用的方法。一般都是已Begin开头End结尾构成一对,异步委托方法,外加两个回调函数和AsyncState参数,组成异步操作的宏观体现。所以要做异步编程,不要忘了委托delegate、Begin,End,AsyncCallBack委托,AsyncState实例(在回调函数中通过IAsyncResult.AsyncState来强制转换),IAsycResult(监控异步),就足以理解异步真谛了

    资源来自网络,分别为:

    http://www.cnblogs.com/ericwen/archive/2008/03/12/1101801.html

    http://developer.51cto.com/art/200908/145541.htm

  • 相关阅读:
    Ajax调用处理页面错误信息500的解决思路
    PHP数据库的增删改
    PHP登录及处理
    PHP数据访问
    PHP数组(正则表达式、数组、预定义数组)
    php函数
    45
    数据库_CRUD操作之读取数据之高级读取
    数据库_CRUD操作之读取数据
    数据库_CRUD操作之修改数据
  • 原文地址:https://www.cnblogs.com/fer-team/p/8036567.html
Copyright © 2011-2022 走看看