【发布时间】:2011-05-25 11:06:11
【问题描述】:
已解决:
我找到了解决方案。见Joe Enzminger's reply for an explanation
再次感谢大家。
ps。该代码用于在线打台球(台球) - Windows(免费)版本here 供任何好奇和勇敢尝试的人使用:)
你好,
我已经实现了客户端应用程序“轮询”以等待服务器通知的 IHttpAsyncHandler。通知是由服务器上的其他“活动”生成的,异步处理程序根本不起作用。
执行步骤为:
IHttpAsyncHandler.BeginProcessRequest
Create AsyncResult instance and add it to a "registered clients" collection
return the AsyncResult
...其他服务器活动将生成通知发送给注册客户端...
AsyncResult.CompleteCall called as a result of the generated notification(s).
IHttpAsyncHandler.EndProcessRequest is called
The notification(s) attached to the AsyncResult are written to the response stream.
问题:
我已经在具有 Windows Server 2008 SP2 和 1 个 cpu 内核的 VM 上的 IIS7 上对此进行了测试。在 12 个客户端注册通知后(在 Async.ashx 上使用 HTTP GET),性能下降到后续客户端无法连接的程度。
当我检查 ASP.NET 性能计数器时,“请求执行”计数器随着每个客户端注册而上升并保持在 12(这似乎是它的最大值 - 可能是每个 CPU 的线程池大小)。
我觉得这很令人困惑。我认为异步处理程序的全部目的是为其他连接释放线程。看来情况并非如此,所以我一定做错了什么!
为什么 ASP.NET 在等待我的 AsyncResult 完成时会占用一个线程?这是配置问题吗?我需要做一些具体的事情来表明这是一个异步处理程序吗?
谢谢你, 尼科斯。
编辑:添加以下代码:
public class AsyncResult : IAsyncResult
{
private AsyncCallback _cb;
private object _state;
private ManualResetEvent _event;
private bool _completed;
private bool _completedsynchronously;
private HttpContext _context;
private byte[] _data;
private int _datalength;
private object _lock = new object();
public AsyncWaitResult(AsyncCallback cb, object state, HttpContext context)
{
_context = context;
_cb = cb;
_state = state;
}
public void Close()
{
if (_event != null)
{
_event.Close();
_event = null;
}
}
public HttpContext Context { get { return _context; } }
public Object AsyncState { get { return _state; } }
public bool CompletedSynchronously { get { return _completedsynchronously; } }
public bool IsCompleted { get { return _completed; } }
public byte[] Data { get { return _data; } }
public int DataLength { get { return _datalength; } }
public WaitHandle AsyncWaitHandle
{
get
{
lock (_lock)
{
if (_event == null)
_event = new ManualResetEvent(_completed);
return _event;
}
}
}
public void CompleteCall(byte[] data, int length, bool completedsynchronously)
{
_data = data;
_datalength = length;
_completedsynchronously = completedsynchronously;
lock (_lock)
{
_completed = true;
if (_event != null)
_event.Set();
}
if (_cb != null)
_cb(this);
}
}
public class Outbound : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object state)
{
AsyncResult asyncresult = new AsyncResult(cb, state, context);
RegisteredClients.Instance.Add(asyncresult);
return asyncresult;
}
public void EndProcessRequest(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
if (result != null)
{
result.Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
result.Context.Response.ContentType = "application/octet-stream";
result.Context.Response.AddHeader("Connection", "keep-alive");
if (result.Data != null)
result.Context.Response.OutputStream.Write(result.Data, 0, result.DataLength);
result.Close();
}
}
public void ProcessRequest(HttpContext context){}
public bool IsReusable { get { return true; } }
}
【问题讨论】:
-
我认为您需要发布更详细的代码。由于未能正确实现异步模式,这听起来像是某种“泄漏”,但很难说。
-
完成了——真的很简单。如果您需要澄清,请告诉我。
-
RegisteredClients.Instance.Add() 不能以任何理由阻止,可以吗?
-
还有一个问题 - 在您使用的模式中,我只会为 completedsynchronously 属性返回“false”。有没有在调用 CompleteCall() 时将该参数设置为 true 的情况?
-
@Joe 不,它没有。我已经先检查过了。它几乎立即返回(不到一毫秒)是的,在某些情况下它可以同步完成。当有未完成的通知时会发生这种情况。我还验证了让它永久返回 false 没有任何区别。 ------ @ZERO:如果这样做,我会感到非常惊讶。如果是这样,它的行为就像一个普通的同步处理程序。我认为 IAsyncResult 进入队列供 asp.net 监控。