C#中的异步调用及异步设计模式(一)

时间:2021-08-03 04:05:50

近期项目中使用了不少异步操作,关于“异步”做个总结。总结的内容大部分都来自于MSDN,还有一些自己的心得。

关于“异步”的使用可分为:使用层面和类库设计层面,细分如下:

一、使用异步方式调用同步方法(使用层面)。

二、使用 IAsyncResult 调用异步方法(使用层面)。

三、基于 IAsyncResult 的异步设计模式(设计层面)。

四、基于事件的异步模式(设计层面)。

关于上述异步编程的几个方面,下面分别做以详述。

一、使用异步方式调用同步方法(使用层面)

.NET Framework 允许您异步调用任何方法。为此,应定义与您要调用的方法具有相同签名的委托;公共语言运行库会自动使用适当的签名为该委托定义 BeginInvoke 和 EndInvoke 方法。BeginInvoke 方法可启动异步调用,EndInvoke 方法检索异步调用的结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用尚未完成,EndInvoke 将一直阻止调用线程,直到异步调用完成后才允许调用线程执行。

该调用方式是使用委托进行异步调用,其实质是:调用“BeginInvoke”方法,公共语言运行库 (CLR) 将对请求进行排队并立即返回到调用方。将对来自线程池的线程调用该目标方法。提交请求的原始线程*地继续与目标方法并行执行,该目标方法是在线程池线程运行的。

在异步调用启动后,在等待异步调用结果的时候,可以进行以下四种方法。

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

[csharp] view plaincopy
  1. using System;  
  2. using System.Threading;  
  3.   
  4. namespace Examples.AdvancedProgramming.AsynchronousOperations  
  5. {  
  6.     public class AsyncMain  
  7.     {  
  8.         public static void Main()  
  9.         {  
  10.             // The asynchronous method puts the thread id here.  
  11.             int threadId;  
  12.   
  13.             // Create an instance of the test class.  
  14.             AsyncDemo ad = new AsyncDemo();  
  15.   
  16.             // Create the delegate.  
  17.             AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);  
  18.   
  19.             // Initiate the asychronous call.  
  20.             IAsyncResult result = caller.BeginInvoke(3000,  
  21.                 out threadId, nullnull);  
  22.   
  23.             Thread.Sleep(0);  
  24.             Console.WriteLine("Main thread {0} does some work.",  
  25.                 Thread.CurrentThread.ManagedThreadId);  
  26.   
  27.             // 调用此方法将会一直等待异步操作完成,并阻塞当前线程。  
  28.             string returnValue = caller.EndInvoke(out threadId, result);  
  29.   
  30.             Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  
  31.                 threadId, returnValue);  
  32.         }  
  33.     }  
  34. }  


 

·                     进行某些操作,然后使用 IAsyncResult..::.AsyncWaitHandle 属性获取 WaitHandle,使用它的 WaitOne 方法(该方法可以设置一个超时时间)一直阻止执行直到发出 WaitHandle 信号,然后调用 EndInvoke。

[csharp] view plaincopy
  1. using System;  
  2. using System.Threading;  
  3.   
  4. namespace Examples.AdvancedProgramming.AsynchronousOperations  
  5. {  
  6.     public class AsyncMain  
  7.     {  
  8.         static void Main()  
  9.         {  
  10.             // The asynchronous method puts the thread id here.  
  11.             int threadId;  
  12.   
  13.             // Create an instance of the test class.  
  14.             AsyncDemo ad = new AsyncDemo();  
  15.   
  16.             // Create the delegate.  
  17.             AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);  
  18.   
  19.             // Initiate the asychronous call.  
  20.             IAsyncResult result = caller.BeginInvoke(3000,  
  21.                 out threadId, nullnull);  
  22.   
  23.             Thread.Sleep(0);  
  24.             Console.WriteLine("Main thread {0} does some work.",  
  25.                 Thread.CurrentThread.ManagedThreadId);  
  26.   
  27.             // 调用此方法将会一直等待异步操作完成,并阻塞当前线程。  
  28.             result.AsyncWaitHandle.WaitOne();  
  29.   
  30.             // Perform additional processing here.  
  31.             // Call EndInvoke to retrieve the results.  
  32.             string returnValue = caller.EndInvoke(out threadId, result);  
  33.   
  34.             Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  
  35.                 threadId, returnValue);  
  36.         }  
  37.     }  
  38. }  


 

·                     进行某些操作,然后轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke。

[csharp] view plaincopy
  1. using System;  
  2. using System.Threading;  
  3.   
  4. namespace Examples.AdvancedProgramming.AsynchronousOperations  
  5. {  
  6.     public class AsyncMain  
  7.     {  
  8.         static void Main()  
  9.         {  
  10.             // The asynchronous method puts the thread id here.  
  11.             int threadId;  
  12.   
  13.             // Create an instance of the test class.  
  14.             AsyncDemo ad = new AsyncDemo();  
  15.   
  16.             // Create the delegate.  
  17.             AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);  
  18.   
  19.             // Initiate the asychronous call.  
  20.             IAsyncResult result = caller.BeginInvoke(3000,  
  21.                 out threadId, nullnull);  
  22.   
  23.             // 等待结果返回  
  24.             while (result.IsCompleted == false)  
  25.             {  
  26.                 Thread.Sleep(10);  
  27.             }  
  28.   
  29.             // Call EndInvoke to retrieve the results.  
  30.             string returnValue = caller.EndInvoke(out threadId, result);  
  31.   
  32.             Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  
  33.                 threadId, returnValue);  
  34.         }  
  35.     }  
  36. }  


 

·                     将用于回调方法的委托传递给 BeginInvoke。异步调用完成后,将在 ThreadPool 线程上执行该方法。该回调方法将调用 EndInvoke。注意:该回调函数的执行是在另外一个线程上。

 

[csharp] view plaincopy
  1. using System;  
  2. using System.Threading;  
  3.   
  4. namespace Examples.AdvancedProgramming.AsynchronousOperations  
  5. {  
  6.     public class AsyncMain   
  7.     {  
  8.         // Asynchronous method puts the thread id here.  
  9.         private static int threadId;  
  10.   
  11.         static void Main() {  
  12.             // Create an instance of the test class.  
  13.             AsyncDemo ad = new AsyncDemo();  
  14.   
  15.             // Create the delegate.  
  16.             AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);  
  17.   
  18.             // Initiate the asychronous call.  Include an AsyncCallback  
  19.             // delegate representing the callback method, and the data  
  20.             // needed to call EndInvoke.  
  21.             IAsyncResult result = caller.BeginInvoke(3000,  
  22.                 out threadId,   
  23.                 new AsyncCallback(CallbackMethod),  
  24.                 caller );  
  25.   
  26.             Console.WriteLine("Press Enter to close application.");  
  27.             Console.ReadLine();  
  28.         }  
  29.   
  30.         // Callback method must have the same signature as the  
  31.         // AsyncCallback delegate.  
  32.         static void CallbackMethod(IAsyncResult ar)   
  33.         {  
  34.             // Retrieve the delegate.  
  35.             AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState;  
  36.   
  37.             // Call EndInvoke to retrieve the results.  
  38.             string returnValue = caller.EndInvoke(out threadId, ar);  
  39.   
  40.             Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  
  41.                 threadId, returnValue);  
  42.         }  
  43.     }  
  44. }  


二、使用 IAsyncResult 调用异步方法(使用层面)

.NET Framework 的许多方面都支持异步编程功能,这些方面包括:

·                     文件 IO、流 IO、套接字 IO。

·                     网络。

·                     远程处理信道(HTTP、TCP)和代理。

·                     使用 ASP.NET 创建的 XML Web services。

·                     ASP.NET Web 窗体。

·                     使用 MessageQueue 类的消息队列。

这些已经实现了异步操作的类或组件,可以直接调用其异步方法(以Begin和End开头)。调用异步方法后等待结果可以参考“异步调用同步方法”的处理。

 

三、基于 IAsyncResult 的异步设计模式(设计层面)

待续...