zoukankan      html  css  js  c++  java
  • 使用委托进行异步编程

    异步委托提供以异步方式调用同步方法的能力。当同步调用一个委托时,“Invoke”方法直接对当前线程调用目标方法。如果编译器支持异步委托,则它将生成“Invoke”方法以及“BeginInvoke”和“EndInvoke”方法。如果调用“BeginInvoke”方法,则公共语言运行库 (CLR) 将对请求进行排队并立即返回到调用方。将对来自线程池的线程调用该目标方法。提交请求的原始线程自由地继续与目标方法并行执行,该目标方法是对线程池线程运行的。如果在对“BeginInvoke”方法的调用中指定了回调方法,则当目标方法返回时将调用该回调方法。在回调方法中,“EndInvoke”方法获取返回值和所有输入/输出参数。如果在调用“BeginInvoke”时未指定任何回调方法,则可以从调用“BeginInvoke”的线程中调用“EndInvoke”。

    要点

    使用用户指定的委托签名,编译器应发出具有“Invoke”、“BeginInvoke”和“EndInvoke”方法的委托类。“BeginInvoke”和“EndInvoke”方法应被修饰为本机的。因为这些方法被标记为本机的,所以 CLR 在类加载时自动提供该实现。加载程序确保它们未被重写。

    使用异步方式调用同步方法

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

    BeginInvoke 方法可启动异步调用。它与您需要异步执行的方法具有相同的参数,另外它还有两个可选参数。第一个参数是一个 AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象可向回调方法传递信息。BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 会返回 IAsyncResult,这个结果可用于监视异步调用进度。

    EndInvoke 方法检索异步调用的结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用尚未完成,EndInvoke 将一直阻止调用线程,直到异步调用完成后才允许调用线程执行。EndInvoke 的参数包括您需要异步执行的方法的 outref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

    注意

    Visual Studio 2005 中的 IntelliSense 功能显示 BeginInvoke 和 EndInvoke 的参数。如果您没有使用 Visual Studio 或类似工具,或您使用的是带有 Visual Studio 2005 的 C#,请参见异步编程概述以获取为这些方法定义的参数的说明。

    本主题中的代码示例演示了四种使用 BeginInvoke 和 EndInvoke 进行异步调用的常用方法。调用 BeginInvoke 之后,您可以执行下列操作:

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

    • 使用 System.IAsyncResult.AsyncWaitHandle 属性获取 WaitHandle,使用它的 WaitOne 方法一直阻止执行直到发出 WaitHandle 信号,然后调用 EndInvoke。

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

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

      要点

      每次都要调用 EndInvoke 来完成异步调用。

    定义测试方法和异步委托

    下面的代码示例演示异步调用同一个长时间运行的方法 TestMethod 的各种方式。TestMethod 方法会显示一条控制台消息,说明它已开始处理,休眠了几秒钟,然后结束。TestMethod 有一个 out 参数,该参数用于演示此种参数添加到 BeginInvoke 和 EndInvoke 的签名中的方式。您可以按同样的方式处理 ref 参数。

    下面的代码示例演示 TestMethod 的定义和名为 AsyncMethodCaller 的、可用来异步调用 TestMethod 的委托。若要编译任何代码示例,必须包括 TestMethod 的定义和 AsyncMethodCaller 委托。

    using System;
    using System.Threading; 
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        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 = Thread.CurrentThread.ManagedThreadId;
                return String.Format("My call time was {0}.", callDuration.ToString());
            }
        }
        // The delegate must have the same signature as the method
        // it will call asynchronously.
        public delegate string AsyncMethodCaller(int callDuration, out int threadId);
    }
    
    

    使用 EndInvoke 等待异步调用

    异步执行方法最简单的方式是通过调用委托的 BeginInvoke 方法来开始执行方法,在主线程上执行一些工作,然后调用委托的 EndInvoke 方法。EndInvoke 可能会阻止调用线程,因为它直到异步调用完成之后才返回。这种技术非常适合文件或网络操作,但是由于 EndInvoke 会阻止它,所以不要从服务于用户界面的线程中调用它。

    using System;
    using System.Threading;
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        public class AsyncMain 
        {
            public static void Main() 
            {
                // The asynchronous method puts the thread id here.
                int threadId;
    
                // Create an instance of the test class.
                AsyncDemo ad = new AsyncDemo();
    
                // Create the delegate.
                AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
           
                // Initiate the asychronous call.
                IAsyncResult result = caller.BeginInvoke(3000, 
                    out threadId, null, null);
    
                Thread.Sleep(0);
                Console.WriteLine("Main thread {0} does some work.",
                    Thread.CurrentThread.ManagedThreadId);
    
                // Call EndInvoke to wait for the asynchronous call to complete,
                // and to retrieve the results.
                string returnValue = caller.EndInvoke(out threadId, result);
    
                Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                    threadId, returnValue);
            }
        }
    }
    
    

    使用 WaitHandle 等待异步调用

    您可以使用 BeginInvoke 返回的 IAsyncResultAsyncWaitHandle 属性来获取 WaitHandle。异步调用完成时会发出 WaitHandle 信号,而您可以通过调用 WaitOne 方法等待它。

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

    using System;
    using System.Threading;
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        public class AsyncMain 
        {
            static void Main() 
            {
                // The asynchronous method puts the thread id here.
                int threadId;
    
                // Create an instance of the test class.
                AsyncDemo ad = new AsyncDemo();
    
                // Create the delegate.
                AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
           
                // Initiate the asychronous call.
                IAsyncResult result = caller.BeginInvoke(3000, 
                    out threadId, null, null);
    
                Thread.Sleep(0);
                Console.WriteLine("Main thread {0} does some work.",
                    Thread.CurrentThread.ManagedThreadId);
    
                // Wait for the WaitHandle to become signaled.
                result.AsyncWaitHandle.WaitOne();
    
                // Perform additional processing here.
                // Call EndInvoke to retrieve the results.
                string returnValue = caller.EndInvoke(out threadId, result);
    
                Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                    threadId, returnValue);
            }
        }
    }
    
    

    轮询异步调用完成

    您可以使用由 BeginInvoke 返回的 IAsyncResultIsCompleted 属性来发现异步调用何时完成。从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许调用线程在异步调用在 ThreadPool 线程上执行时继续执行。

    using System;
    using System.Threading;
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        public class AsyncMain 
        {
            static void Main() {
                // The asynchronous method puts the thread id here.
                int threadId;
    
                // Create an instance of the test class.
                AsyncDemo ad = new AsyncDemo();
    
                // Create the delegate.
                AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
           
                // Initiate the asychronous call.
                IAsyncResult result = caller.BeginInvoke(3000, 
                    out threadId, null, null);
    
                // Poll while simulating work.
                while(result.IsCompleted == false) {
                    Thread.Sleep(10);
                }
    
                // Call EndInvoke to retrieve the results.
                string returnValue = caller.EndInvoke(out threadId, result);
    
                Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                    threadId, returnValue);
            }
        }
    }
    
    

    异步调用完成时执行回调方法

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

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

    using System;
    using System.Threading;
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        public class AsyncMain 
        {
            // Asynchronous method puts the thread id here.
            private static int threadId;
    
            static void Main() {
                // Create an instance of the test class.
                AsyncDemo ad = new AsyncDemo();
    
                // Create the delegate.
                AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
           
                // Initiate the asychronous call.  Include an AsyncCallback
                // delegate representing the callback method, and the data
                // needed to call EndInvoke.
                IAsyncResult result = caller.BeginInvoke(3000,
                    out threadId, 
                    new AsyncCallback(CallbackMethod),
                    caller );
    
                Console.WriteLine("Press Enter to close application.");
                Console.ReadLine();
            }
            
            // Callback method must have the same signature as the
            // AsyncCallback delegate.
            static void CallbackMethod(IAsyncResult ar) 
            {
                // Retrieve the delegate.
                AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState;
    
                // Call EndInvoke to retrieve the results.
                string returnValue = caller.EndInvoke(out threadId, ar);
    
                Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                    threadId, returnValue);
            }
        }
    }
    

    异步委托编程示例

    下面的代码示例通过使用求解某些数字因子的类演示如何使用 .NET 异步编程。此示例定义了一个使用单一方法 Factorize 来计算指定数字的主要因子的类。此示例还定义了一个名为 AsyncFactorCaller 的、签名与 Factorize 方法的签名匹配的委托。DemonstrateAsyncPattern 类中的方法将使用此委托来异步调用 Factorize 方法。FactorizeNumberUsingCallback 方法演示如何使用 AsyncCallback 委托来结束异步操作并获得结果。FactorizeNumberAndWait 方法演示如何定期轮询以确定操作是否已完成。

    示例

    using System;
    using System.Threading;
    using System.Runtime.Remoting.Messaging;
    
    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {
        // Create a class that factors a number.
        public class PrimeFactorFinder
        {
           public static bool Factorize(
                        int number,
                        ref int primefactor1,
                        ref int primefactor2)
           {
              primefactor1 = 1;
              primefactor2 = number;
    
              // Factorize using a low-tech approach.
              for (int i=2;i<number;i++)
              {
                 if (0 == (number % i))
                 {
                    primefactor1 = i;
                    primefactor2 = number / i;
                    break;
                 }
              }
              if (1 == primefactor1 )
                 return false;
              else
                 return true   ;
           }
        }
    
        // Create an asynchronous delegate that matches the Factorize method.
        public delegate bool AsyncFactorCaller (
                 int number, 
                 ref int primefactor1,
                 ref int primefactor2);
    
        public class DemonstrateAsyncPattern
        {
            // The waiter object used to keep the main application thread
            // from terminating before the callback method completes.
            ManualResetEvent waiter;
            
            // Define the method that receives a callback when the results are available.
            public void FactorizedResults(IAsyncResult result)
               {
                  int factor1=0;
                  int factor2=0; 
            
                  // Extract the delegate from the 
                  // System.Runtime.Remoting.Messaging.AsyncResult.
                  AsyncFactorCaller factorDelegate = (AsyncFactorCaller)((AsyncResult)result).AsyncDelegate;
                  int number = (int) result.AsyncState;
                  // Obtain the result.
                  bool answer = factorDelegate.EndInvoke(ref factor1, ref factor2, result);
                  // Output the results.
                  Console.WriteLine("On CallBack: Factors of {0} : {1} {2} - {3}", 
                      number, factor1, factor2, answer);
                  waiter.Set();
               }
    
           // The following method demonstrates the asynchronous pattern using a callback method.
           public void FactorizeNumberUsingCallback()
           {
              AsyncFactorCaller factorDelegate = new AsyncFactorCaller (PrimeFactorFinder.Factorize);
              int number = 1000589023;
              int temp=0; 
              // Waiter will keep the main application thread from 
              // ending before the callback completes because
              // the main thread blocks until the waiter is signaled
              // in the callback.
               waiter = new ManualResetEvent(false);
    
              // Define the AsyncCallback delegate.
              AsyncCallback callBack = new AsyncCallback(this.FactorizedResults);
    
              // Asynchronously invoke the Factorize method.
              IAsyncResult result = factorDelegate.BeginInvoke(
                                   number, 
                                   ref temp, 
                                   ref temp, 
                                   callBack, 
                                   number); 
    
              // Do some other useful work while 
              // waiting for the asynchronous operation to complete.
    
              // When no more work can be done, wait.
              waiter.WaitOne();
           }
    
           // The following method demonstrates the asynchronous pattern 
           // using a BeginInvoke, followed by waiting with a time-out.
           public void FactorizeNumberAndWait()
           {
              AsyncFactorCaller factorDelegate = new AsyncFactorCaller (PrimeFactorFinder.Factorize);
    
              int number = 1000589023;
              int temp=0; 
    
              // Asynchronously invoke the Factorize method.
              IAsyncResult result = factorDelegate.BeginInvoke(
                                number, 
                                ref temp, 
                                ref temp, 
                                null, 
                                null); 
                                
              while (!result.IsCompleted)
              {
                // Do any work you can do before waiting.
                result.AsyncWaitHandle.WaitOne(10000, false);
              }
              // The asynchronous operation has completed.
              int factor1=0;
              int factor2=0; 
    
             // Obtain the result.
             bool answer = factorDelegate.EndInvoke(ref factor1, ref factor2, result);
    
             // Output the results.
             Console.WriteLine("Sequential : Factors of {0} : {1} {2} - {3}", 
                               number, factor1, factor2, answer);
           }
    
           public static void Main()
           {
              DemonstrateAsyncPattern demonstrator = new DemonstrateAsyncPattern();
              demonstrator.FactorizeNumberUsingCallback();
              demonstrator.FactorizeNumberAndWait();
           }
        }
    }
  • 相关阅读:
    基础类库积累--Encrypt类
    基础类库积累--Random类
    基础类库积累--HTTP操作类
    基础类库积累--ExeclHelper类
    webpack-dev-server配置https
    HBuilderX代码缩进问题
    前端每日一知之css隐藏页面元素
    前端每日一知之web攻击方式
    前端每日一知之css常用布局单位
    前端每日一知之css选择器
  • 原文地址:https://www.cnblogs.com/go-jzg/p/6379712.html
Copyright © 2011-2022 走看看