ASP.NET 页面异步任务

PageAsyncTask是任务类,通过 Page.RegisterAsyncTask来注册,Page.ExecuteRegisteredAsyncTasks()调用

页面代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" AsyncTimeout="4" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Asynchronous Task Example</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <span id="TaskMessage" runat=server>
      </span>
    </div>
    </form>
</body>
</html>

后置代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // 定义异步任务.
        SlowTask slowTask1 = new SlowTask();
        SlowTask slowTask2 =new SlowTask();
        SlowTask slowTask3 =new SlowTask();

        PageAsyncTask asyncTask1 = new PageAsyncTask(slowTask1.OnBegin, slowTask1.OnEnd, slowTask1.OnTimeout, "Async1", true);
        PageAsyncTask asyncTask2 = new PageAsyncTask(slowTask2.OnBegin, slowTask2.OnEnd, slowTask2.OnTimeout, "Async2", true);
        PageAsyncTask asyncTask3 = new PageAsyncTask(slowTask3.OnBegin, slowTask3.OnEnd, slowTask3.OnTimeout, "Async3", true);

        //注册页面异步任务.
        //单个任务如果超过页面定义的AsyncTimeout,就会调用Timeout委托
        Page.RegisterAsyncTask(asyncTask1);
        Page.RegisterAsyncTask(asyncTask2);
        Page.RegisterAsyncTask(asyncTask3);

        DateTime tStart = DateTime.Now;
        // 执行注册的异步方法,会阻塞线程,直到所有注册方法执行完毕或者超时
        Page.ExecuteRegisteredAsyncTasks();
        DateTime tEnd = DateTime.Now;

        TaskMessage.InnerHtml =
            "Task1:"+slowTask1.GetAsyncTaskProgress() + "<br>" +
            "Task2:"+slowTask2.GetAsyncTaskProgress() + "<br>" +
            "Task3:"+slowTask3.GetAsyncTaskProgress() + "<br/>"+
             "总开始时间:" + tStart + "  总结束时间:" + tEnd;
    }

    public class SlowTask
    {
        private static Random rand = new Random();
        private String _taskprogress;
        private AsyncTaskDelegate _dlgt;

        // Create delegate.
        protected delegate void AsyncTaskDelegate();

        public String GetAsyncTaskProgress()
        {
            return _taskprogress;
        }

        //实际执行的耗时操作
        public void ExecuteAsyncTask()
        {
            //随即生产1-5秒模拟调用耗时
            int second = rand.Next(1, 5);
            Thread.Sleep(TimeSpan.FromSeconds(second));
        }

        //异步调用开始时调用
        //此方法内一般不放耗时操作,而是内部新建线程执行
        public IAsyncResult OnBegin(object sender, EventArgs e,
            AsyncCallback cb, object extraData)
        {
            _taskprogress = "开始时间: " + DateTime.Now + ". ";
            //这里定义耗时方法的委托,并开始异步执行
            //虽然直接将耗时操作直接写在OnBegin可以有相同的效果,但是使用单独委托可以更灵活
            //比如可以通过委托传递由外部定义的耗时操作
            _dlgt = new AsyncTaskDelegate(ExecuteAsyncTask);
            IAsyncResult result = _dlgt.BeginInvoke(cb, extraData);

            return result;
        }

        // 异步调用结束时被调用
        public void OnEnd(IAsyncResult ar)
        {
            _taskprogress += "完成时间: " + DateTime.Now;
            _dlgt.EndInvoke(ar);
        }

        //异步调用在指定时间未完成时被调用(即超时)
        public void OnTimeout(IAsyncResult ar)
        {
            _taskprogress += "异步操作超时";
        }
    }
}

用处:
使用异步任务可以最大限度利用多核服务器

还可以利用ExecuteRegisteredAsyncTasks的阻塞功能实现简单Server-Push效果

思路:

  服务端: 可以将异步方法放入某个类实例,方法中使用ManualResetEvent或其他同步类,阻塞方法执行,将类实例放入全局变量中,如Dictionary,当满足某些条件时(如某个请求),在全局变量中找出对应类,通过类的公开方法释放ManualResetEvent锁定返回是数据

 客户端:根据服务端返回的信息作出不同反应,不管是超时还是正常得到数据,都再向服务器开ajax请求,等待服务器新的响应

posted @ 2012-07-05 23:31  Bug山Bug海  阅读(457)  评论(0编辑  收藏  举报