异步编程模型--使用 IAsyncResult 对象

先推荐阅读下面的资料:

MSDN:异步编程设计模式

IBM developerworks: 使用异步 I/O 大大提高应用程序的性能

参考博文:

 

1、正确使用异步操作 

2、Lab:体会ASP.NET异步处理请求的效果

3、WCF中的异步调用

4、WCF从理论到实践(11)-异步

5、异步编程

 

.NET Framework 为异步操作提供两种设计模式:
1、使用 IAsyncResult 对象的异步操作。
2、使用事件的异步操作。

IAsyncResult接口类型

 

    [ComVisible(true)]
    
public interface IAsyncResult
    {
        
// 摘要:
        
//     获取用户定义的对象,它限定或包含关于异步操作的信息。
        
//
        
// 返回结果:
        
//     用户定义的对象,它限定或包含关于异步操作的信息。
        object AsyncState { get; }
        
//
        
// 摘要:
        
//     获取用于等待异步操作完成的 System.Threading.WaitHandle。
        
//
        
// 返回结果:
        
//     用于等待异步操作完成的 System.Threading.WaitHandle。
        WaitHandle AsyncWaitHandle { get; }
        
//
        
// 摘要:
        
//     获取异步操作是否同步完成的指示。
        
//
        
// 返回结果:
        
//     如果异步操作同步完成,则为 true;否则为 false。
        bool CompletedSynchronously { get; }
        
//
        
// 摘要:
        
//     获取异步操作是否已完成的指示。
        
//
        
// 返回结果:
        
//     如果操作完成则为 true,否则为 false。
        bool IsCompleted { get; }
    }


下面是使用 IAsyncResult 对象的测试代码。

 public delegate string AsyncDelegate(int callDuration, out int threadId);
    
class Program
    {
        
static void Main(string[] args)
        {
            Fun1();
            Console.ReadLine();
        }

        
private static int threadId;

        
//阻塞等待   使用 EndInvoke 等待异步调用  
        static void Fun1()
        {
            
//创建示例类的实例。
            AsyncDemo ad = new AsyncDemo();
            
// 创建委托
            AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
            
// 委托在这里开始异步调用。
            IAsyncResult ar = dlgt.BeginInvoke(5000,out threadId, nullnull);
            
//人为的线程阻塞。
            Thread.Sleep(0);
            Console.WriteLine(
"主线程 {0}开始工作",Thread.CurrentThread.ManagedThreadId);
            
// 委托开始EndInvoke调用,这个过程会使主线程等待异步调用完成并返回结果。
            string ret = dlgt.EndInvoke(out threadId, ar);
            Console.WriteLine(
"异步线程 {0},返回值 \"{1}\".", threadId, ret);
            Console.WriteLine(
"主线程{0}结束工作", Thread.CurrentThread.ManagedThreadId);
        }
        
        
//阻塞等待  使用 WaitHandle 等待异步调用
        static void Fun2()
        {
            AsyncDemo ad 
= new AsyncDemo();
            AsyncDelegate dlgt 
= new AsyncDelegate(ad.TestMethod);
            IAsyncResult ar 
= dlgt.BeginInvoke(5000,out threadId, nullnull);
            Thread.Sleep(
0);
            Console.WriteLine(
"主线程 {0}开始工作", Thread.CurrentThread.ManagedThreadId);
            
//主线程在这里等待,直到异步线程执行完。
            ar.AsyncWaitHandle.WaitOne();
            
// 和前一方案的区别在于,你可以在异步调用完成后,获取异步调用返回值之前
            
//在这里做点任何你想作的事。
            
//调用EndInvoke获取异步调用的返回结果.
            string ret = dlgt.EndInvoke(out threadId, ar);
            Console.WriteLine(
"异步线程 {0},返回值 \"{1}\".", threadId, ret);
            Console.WriteLine(
"主线程{0}结束工作", Thread.CurrentThread.ManagedThreadId);
        }

        
//轮询状态    轮询异步调用完成
        static void Fun3()
        {
            AsyncDemo ad 
= new AsyncDemo();
            AsyncDelegate dlgt 
= new AsyncDelegate(ad.TestMethod);
            IAsyncResult ar 
= dlgt.BeginInvoke(5000,out threadId, nullnull);
            Console.WriteLine(
"主线程 {0}开始工作", Thread.CurrentThread.ManagedThreadId);
            
//这里每隔10毫秒就检测(轮询)一下异步执行的状态,
            
//直到异步调用完成,IsCompleted的值变为ture为止。
            while (ar.IsCompleted == false)
            {
                Thread.Sleep(
10);
            }

            
//还记得微软的那个善意的提醒吗?虽然IsCompleted为true了,
            
//我们还是调用一下EndInvoke,来获取返回值。
            string ret = dlgt.EndInvoke(out threadId, ar);
            Console.WriteLine(
"异步线程 {0},返回值 \"{1}\".", threadId, ret);
            Console.WriteLine(
"主线程{0}结束工作", Thread.CurrentThread.ManagedThreadId);
        }

        
//通知机制    异步调用完成时执行回调方法
        static void Fun4()
        {
            AsyncDemo ad 
= new AsyncDemo();
            AsyncDelegate dlgt 
= new AsyncDelegate(ad.TestMethod);
            
//注意第三个参数,这就是我们要用到的回调方法。
            
//第四个参数更为有趣,它可以是任何Object对象,这里它就是
            
//执行异步调用的委托本身,把委托本身传递进去的原因在下面可以看到。
            Console.WriteLine("主线程 {0}开始工作", Thread.CurrentThread.ManagedThreadId);
            IAsyncResult ar 
= dlgt.BeginInvoke(5000,out threadId, new AsyncCallback(CallbackMethod), dlgt);
            Console.WriteLine(
"主线程 {0}结束工作", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }
        
//回调函数必须严格的遵照AsyncCallback委托的签名。
        static void CallbackMethod(IAsyncResult ar)
        {
            
//在这里,上面那个dlgt作为参数的作用得到了体现,原来它就是为了完成对EndInvoke的调用啊。
            AsyncDelegate dlgt = (AsyncDelegate)ar.AsyncState;
            
//通过对EndInvoke的调用获取返回值。
            string ret = dlgt.EndInvoke(out threadId, ar);
            Console.WriteLine(
"异步线程 {0},返回值 \"{1}\".", threadId, ret);
        }
    }
    
//使用异步编程模型 
    public class AsyncDemo
    {
        
public string TestMethod(int callDuration, out int threadId)
        {
            Console.WriteLine(
"异步方法开始工作");
            Thread.Sleep(callDuration);
            threadId 
= Thread.CurrentThread.ManagedThreadId; 
            
return "异步方法执行时间 " + callDuration.ToString();
        }
    }

 执行结果:

Fun1--------------------

异步方法开始工作
主线程 10开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun2---------------------
异步方法开始工作
主线程 10开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun3---------------------

主线程 10开始工作
异步方法开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun4---------------------
主线程 10开始工作
主线程 10结束工作
异步方法开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
--------------------------

工作当中有一个调用ActiveMQ的产品,每天大概是上万的消息。压力也不是很大。最近总是出现调用MQ阻塞的情况。负责MQ的同事也没有找到原因。

我是想寻找一个消息队列的代替品。 上面的第四个方法,异步线程不阻塞调用线程,当然调用线程也无需处理调用结果,貌似可以作为一个代替方案。

 

 

 

 

 

 

 


 

posted @ 2010-01-07 09:46  青羽  阅读(1235)  评论(4编辑  收藏  举报