假设异步页的后台代码如下,我将BeginAsyncOperation方法中的代码
cb(t);
注释掉后,访问该异步页时,就陷入长期的等待中。我的问题是:为什么会这样?我猜测:
HttpRuntime在执行异步调用时,负责激活异步调用的主方法,
在激活BeginEventHandler代理的方法后,就处于等待状态。
而能够结束等待状态的条件就是:所有注册了异步执行的方法都已成功返回,
或者执行注销。
要做到这些,就要求在异步线程中返回一个结束信号。
这个结束信号由执行BeginAsyncOperation方法中的参数AsyncCallback cb
所包含的代理方法后发出,而不是BeginAsyncOperation方法的返回值。
这也说明,BeginAsyncOperation代理的BeginAsyncOperation方法的返回值IAsyncResult对象,
并不能告诉ASP.NET:我的任务完成了。
可是很奇怪,这个返回值到底有什么用?如何使用?
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;public partial class _Default : System.Web.UI.Page
{
int i;
string ii; void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
} IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state)
{
i++;
AsyncResult t = new AsyncResult();
t.IsCompleted = true;//不论设定false还是true,结果相同
//cb(t);
return t;
}
void EndAsyncOperation(IAsyncResult ar)
{
ii = i.ToString();
} protected void Page_PreRenderComplete(object sender, EventArgs e)
{
Label1.Text = ii;
}
}public class AsyncResult : IAsyncResult
{
private object _asyncState;
private bool _isCompleted; public AsyncResult() { } public object AsyncState
{
get { return this._asyncState; }
set { this._asyncState = value; }
} public bool IsCompleted
{
get { return this._isCompleted; }
set { this._isCompleted = value; }
} object IAsyncResult.AsyncState
{ get { return this._asyncState; } } WaitHandle IAsyncResult.AsyncWaitHandle
{ get { return null; } } bool IAsyncResult.CompletedSynchronously
{ get { return false; } } bool IAsyncResult.IsCompleted
{ get { return this._isCompleted; } }
}
cb(t);
注释掉后,访问该异步页时,就陷入长期的等待中。我的问题是:为什么会这样?我猜测:
HttpRuntime在执行异步调用时,负责激活异步调用的主方法,
在激活BeginEventHandler代理的方法后,就处于等待状态。
而能够结束等待状态的条件就是:所有注册了异步执行的方法都已成功返回,
或者执行注销。
要做到这些,就要求在异步线程中返回一个结束信号。
这个结束信号由执行BeginAsyncOperation方法中的参数AsyncCallback cb
所包含的代理方法后发出,而不是BeginAsyncOperation方法的返回值。
这也说明,BeginAsyncOperation代理的BeginAsyncOperation方法的返回值IAsyncResult对象,
并不能告诉ASP.NET:我的任务完成了。
可是很奇怪,这个返回值到底有什么用?如何使用?
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;public partial class _Default : System.Web.UI.Page
{
int i;
string ii; void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
} IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state)
{
i++;
AsyncResult t = new AsyncResult();
t.IsCompleted = true;//不论设定false还是true,结果相同
//cb(t);
return t;
}
void EndAsyncOperation(IAsyncResult ar)
{
ii = i.ToString();
} protected void Page_PreRenderComplete(object sender, EventArgs e)
{
Label1.Text = ii;
}
}public class AsyncResult : IAsyncResult
{
private object _asyncState;
private bool _isCompleted; public AsyncResult() { } public object AsyncState
{
get { return this._asyncState; }
set { this._asyncState = value; }
} public bool IsCompleted
{
get { return this._isCompleted; }
set { this._isCompleted = value; }
} object IAsyncResult.AsyncState
{ get { return this._asyncState; } } WaitHandle IAsyncResult.AsyncWaitHandle
{ get { return null; } } bool IAsyncResult.CompletedSynchronously
{ get { return false; } } bool IAsyncResult.IsCompleted
{ get { return this._isCompleted; } }
}
Asynchronous Pages in ASP.NET 2.0
如果cb(t)不调用,那么EndAsyncOperation根本就不会被调用到,阻塞是必然.
我没有去确定cb是不是就是EndAsyncOperation,但是
AsyncCallback的委托声明跟EndAsyncOperation这个方法是匹配的.你可以在调试的时候在
return t;
处设置一个断点,然后在
ii = i.ToString();
设置另一个断点,如果是调用了cb(t),你会发现程序会在后一个断点处先停住,F5继续之后会在前一个断点停住.
cb这个异步的操作是让另一个异步操作去做回调的,在这个异步操作执行完成之后,来执行cb,
因此cb绝对不该在BeginAsyncOperation被主动调用.
但解决不了我的追究我看了反编译代码,调用过程很难跟踪。所以,放弃了。
但我从多方面的其他研究得出一个结论:
异步事件虽然与异步执行相关,但执行的过程受到ASP.NET的机制所控制,不能等同于异步执行。同时,异步事件的begin方法的委托参数AsyncCallback cb必须被调用,才能使异步事件完成回调。具体原理必须从微软的相关类库的源代码中寻求答案。