zoukankan      html  css  js  c++  java
  • 多个异步任务串行化的思考和研究(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;
            }
        }
    
    }
    
  • 相关阅读:
    网络七层
    微信小程序开发工具 常用快捷键
    BZOJ 1026 windy数 (数位DP)
    BZOJ 1026 windy数 (数位DP)
    CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)
    CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)
    HDU 3709 Balanced Number (数位DP)
    HDU 3709 Balanced Number (数位DP)
    UVA 11361 Investigating Div-Sum Property (数位DP)
    UVA 11361 Investigating Div-Sum Property (数位DP)
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/2690469.html
Copyright © 2011-2022 走看看