好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

多个异步任务串行化的思考和研究(Silverlight, AJAX场景)

多个异步任务串行化的思考和研究(Silverlight, AJAX场景)

内容摘要

异步编程在我们日常的开发工作中经常遇到的场景。现在的应用程序,很难说不需要进行异步的一些任务。例如网络服务的调用。典型的情况就在于Silverlight和AJAX场景中。

一个异步任务的执行,可能很简单,.NET有大约4种所谓的异步编程模型,最常见的是基于回调的方式。每个异步任务,都是独立的一个线程,这些任务之间,默认情况下不会有依赖,也不会有先后顺序的概念的。他们一般是同时发出去的请求,然后根据具体每个任务的情况,会逐渐返回结果。但这里有一个情况就是,他们返回结果的时间是不可预期的。

但是如果我们需要有多个异步任务,而且这些任务之间本身存在一定的先后次序,例如A先执行完,然后才能执行B,甚至A的结果要作为B的输入。那么这个时候应该怎么做呢?

在.NET内部的实现中,可以通过在任务之间互相嵌套的方式简单地实现,但其代码向当地不易于阅读和扩展。

为此,我们做了一些封装和改进。本次演讲,我首先讲解了默认的一些实现方式,然后着重演示了两种扩展

1.使用AsyncTaskFactory 这个组件  http://nuget.org/packages/AsyncTaskFactory

2.使用AsyncCTP这个组件: http:// www.microsoft.com/en-us/download/details.aspx?id=9983

本次演讲的最后,还讲解了如何在AJAX应用中使用队列的方式来实现多个异步任务的串行化。

讲义地址

http://sdrv.ms/Sw7ELi

视频地址

演示代码:

完整源代码请通过这里下载: https://files.cnblogs.com/chenxizhang/AsyncQueueSample.zip  (需要Visual Studio 2010+Silvelight 4.0 Toolkit)

请结合视频理解代码

 服务代码 
 using  System;
 using  System.Collections.Generic;
 using  System.Linq;
 using  System.Web;
 using  System.Web.Services;
 using  System.Threading;

 namespace  AsyncQueueSample.Web
{
     /// <summary> 
     /// 这个例子用来演示多个异步任务的串行化,这里只是简单地模拟了一个长时间执行的方法,使用线程休眠 
     /// 作者:陈希章 
     /// 时间:2012年9月 
     /// 反馈:ares@xizhang.com 
     /// </summary> 
    [WebService(Namespace =  "http://tempuri.org/" )]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem( false )]
     // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.  
    [System.Web.Script.Services.ScriptService]
     public   class  SampleWebService : System.Web.Services.WebService
    {

        [WebMethod]
         public   string  HelloWorld()
        {

            Thread.Sleep(5000);
             return   "Hello World" ;
        }


        [WebMethod]
         public   string  HelloWorld2()
        {

            Thread.Sleep(2000);
             return   "Hello World 2" ;

        }

        [WebMethod]
         public   string  HelloWorld3()
        {

            Thread.Sleep(2000);
             return   "Hello World 3" ;

        }
    }
}
 
 
 界面代码 
 using  System;
 using  System.Linq;
 using  System.ServiceModel.DomainServices.Client;
 using  System.Threading.Tasks;
 using  System.Windows;
 using  System.Windows.Controls;

 namespace  AsyncQueueSample
{
     /// <summary> 
     /// 这个例子演示了如何实现多个异步任务的串行化 
     /// 作者:陈希章 
     /// 时间:2012年9月 
     /// 反馈:ares@xizhang.com 
     /// </summary> 
     public   partial   class  MainPage : UserControl
    {
         public  MainPage()
        {
            InitializeComponent();
        }


         /// <summary> 
         /// 这是常规的并行方式,多个异步调用彼此是没有关联的,同时发出请求 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
         private   void  btASync_Click( object  sender, RoutedEventArgs e)
        {
            var proxy =  new  localhost.SampleWebServiceSoapClient();
            proxy.HelloWorldCompleted += (o, a) => { MessageBox.Show(a.Result); };
            proxy.HelloWorldAsync(); //发出异步请求 

            proxy.HelloWorld2Completed += (o, a) => { MessageBox.Show(a.Result); };
            proxy.HelloWorld2Async();


        }
         /// <summary> 
         /// 这是常规实现的串行方式,在任务之间手工实现顺序,耦合性很高 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
         private   void  btNormal_Click( object  sender, RoutedEventArgs e)
        {
            var proxy =  new  localhost.SampleWebServiceSoapClient();
            proxy.HelloWorldCompleted += (o, a) => //第一个任务的回调 
            {
                MessageBox.Show(a.Result);

                proxy.HelloWorld2Completed += (o1, a1) => //第二个任务的回调 
                {
                    MessageBox.Show(a1.Result);

                    proxy.HelloWorld3Completed += (o2, a2) =>
                    {
                        MessageBox.Show(a2.Result);
                    };

                    proxy.HelloWorld3Async();

                };

                proxy.HelloWorld2Async();
            };

            proxy.HelloWorldAsync();
        }

         /// <summary> 
         /// 使用AsyncTaskFactory改进的做法 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
         private   void  btAsyncTaskFactory_Click( object  sender, RoutedEventArgs e)
        {
            var proxy =  new  localhost.SampleWebServiceSoapClient();
            var task1 =  new  AsyncAction( "task 1" );
            task1.SetAction(() =>
            {
                proxy.HelloWorldCompleted += (o, a) => { MessageBox.Show(a.Result); task1.OnCompleted(); };
                proxy.HelloWorldAsync();
            });

            var task2 =  new  AsyncAction( "task 2" );
            task2.SetAction(() =>
            {
                proxy.HelloWorld2Completed += (o, a) => { MessageBox.Show(a.Result); task2.OnCompleted(); };
                proxy.HelloWorld2Async();
            });


            var task3 =  new  AsyncAction( "task 3" );
            task3.SetAction(() =>
            {
                proxy.HelloWorld3Completed += (o, a) => { MessageBox.Show(a.Result); task3.OnCompleted(); };
                proxy.HelloWorld3Async();
            });


            var runner =  new  AsyncActionRunner(task1, task3, task2);
            runner.Execute();
        }

         /// <summary> 
         /// 使用AsyncCTP改进的做法 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
        async  private   void  btAsyncCTP_Click( object  sender, RoutedEventArgs e)
        {
            var proxy =  new  localhost.SampleWebServiceSoapClient()  as  localhost.SampleWebServiceSoap;

            var result1 = await Task<localhost.HelloWorldResponse>.Factory.FromAsync(
                proxy.BeginHelloWorld( new  localhost.HelloWorldRequest(),  null ,  null ),
                proxy.EndHelloWorld);

            MessageBox.Show(result1.Body.HelloWorldResult);

            var result3 = await Task<localhost.HelloWorld3Response>.Factory.FromAsync(
                proxy.BeginHelloWorld3( new  localhost.HelloWorld3Request(),  null ,  null ),
                proxy.EndHelloWorld3);
            MessageBox.Show(result3.Body.HelloWorld3Result);

            var result2 = await Task<localhost.HelloWorld2Response>.Factory.FromAsync(
                proxy.BeginHelloWorld2( new  localhost.HelloWorld2Request(),  null ,  null ),
                proxy.EndHelloWorld2);
            MessageBox.Show(result2.Body.HelloWorld2Result);

        }

         /// <summary> 
         /// 标准的RIA Service调用的做法 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
         private   void  btRIAService_Click( object  sender, RoutedEventArgs e)
        {
            var ctx =  new  Web.SampleDomainContext();
            ctx.Load<Web.Employee>(ctx.GetEmployeesQuery(), result =>
            {
                MessageBox.Show(result.Entities.FirstOrDefault().FirstName);
            },  true );

            MessageBox.Show( "加载完成" );
        }

         /// <summary> 
         /// 使用AsyncCTP改进的RIA Service调用的做法 
         /// </summary> 
         /// <param name="sender"></param> 
         /// <param name="e"></param> 
        async  private   void  btAsyncCTPRIA_Click( object  sender, RoutedEventArgs e)
        {
            var ctx =  new  Web.SampleDomainContext();
            var result = await ctx.Load<Web.Employee>(ctx.GetEmployeesQuery()).AsTask();
            MessageBox.Show(result.Entities.FirstOrDefault().FirstName);



            MessageBox.Show( "加载完成" );
        }

    }

     /// <summary> 
     /// 对于RIA Service的一个扩展方法 
     /// </summary> 
     public   static   class  OperationExtensions
    {
         public   static  Task<T> AsTask<T>( this  T operation)
           where  T : OperationBase
        {
            TaskCompletionSource<T> tcs =
               new  TaskCompletionSource<T>(operation.UserState);

            operation.Completed += (sender, e) =>
            {
                 if  (operation.HasError && !operation.IsErrorHandled)
                {
                    tcs.TrySetException(operation.Error);
                    operation.MarkErrorAsHandled();
                }
                 else   if  (operation.IsCanceled)
                {
                    tcs.TrySetCanceled();
                }
                 else 
                {
                    tcs.TrySetResult(operation);
                }
            };

             return  tcs.Task;
        }
    }

}

分类:  网络开发和设计 ,  WPF或者Silverligh ,  fmplan-02 - Developement Practice-02-6-Best Practice

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于多个异步任务串行化的思考和研究(Silverlight, AJAX场景)的详细内容...

  阅读:38次