随笔 - 55, 评论 - 298, 引用 - 17

导航

关于

我是新人,: )

每月存档

最新留言

  • re:Last day at Microsoft
    <p><a href="http://www.moretiffany.com/">tiffany jewelry</a> Choose, buy...
    by sibat0705(注册) on 2010/3/12 20:48:58
  • bVSVKxjrysxCAx
    zKTeMu &lt;a href=&quot;http://jmvdsaxpwywz.com/&quot;&gt;jmvdsaxpwywz&lt;/a&am...
    by algkkzvif(匿名) on 2010/2/21 22:53:15
  • DLXXSrOqat
    F3OQLk &lt;a href=&quot;http://pfpvdtnczscw.com/&quot;&gt;pfpvdtnczscw&lt;/a&am...
    by sfxnoylvca(匿名) on 2010/2/21 21:28:18
  • iNOutySOJKTsFyl
    kSPmy1 &lt;a href=&quot;http://kdajmdtvcxfu.com/&quot;&gt;kdajmdtvcxfu&lt;/a&am...
    by lydyggun(匿名) on 2010/2/21 20:21:46
  • mDUfBYTmJjTiGrv
    IXumnI &lt;a href=&quot;http://lamuwgvmprtw.com/&quot;&gt;lamuwgvmprtw&lt;/a&am...
    by gacyafcvtas(匿名) on 2010/2/14 4:47:26
  • oiUMbbvrAlLbcr
    ot9Ga3 &lt;a href=&quot;http://nwawfslgnomg.com/&quot;&gt;nwawfslgnomg&lt;/a&am...
    by cvalpp(匿名) on 2010/2/14 4:46:45
  • re:Last day at Microsoft
    写的真好,看了觉得很受到启发,谢谢,
    by Zheying Zheng(匿名) on 2010/2/4 10:35:20
  • re:REST API的身份验证(Authentication)
    <p>顶</p>
    by kekesoft(注册) on 2010/1/27 20:27:43
  • re:Last day at Microsoft
    祝你好运啊
    by Eric v(匿名) on 2010/1/24 1:53:34
  • re:Last day at Microsoft
    鄙人正在打算内部调动,跨过欢德福卡海峡去西雅图呢, 以后互通有无,常联系.
    by Charlie 木匠(匿名) on 2010/1/11 4:23:23
  • re:Last day at Microsoft
    Good luck, buddy.
    by Huimiao Liu(匿名) on 2010/1/10 20:18:24
  • re:Last day at Microsoft
    &lt;p&gt;Oops,you are right. 改正了。&lt;/p&gt;
    by demonfox(匿名) on 2010/1/10 18:22:13
  • re:Last day at Microsoft
    2006年8月14日起至2009年1月8日止 是2010年吧
    by q(匿名) on 2010/1/10 14:59:53
  • re:Last day at Microsoft
    &quot;永远选择你最感兴趣的项目而不是升职空间等所谓的职业发展前景&quot; -- 说的很好!Good luck!
    by CoderZh(匿名) on 2010/1/8 20:49:26
  • re:Chrome OS和Android的背后
    Google当然不是在传统的操作系统上去跟微软计算,手机操作系统,Windows CE是公认的烂,Google在这里竞争没有什么不可以。Chrome OS更多的是Google云计算战略的一部分,人家根...
    by 啊(匿名) on 2009/12/22 13:14:12

广告

 

ASP.NET中你可以通过继承IHttpHandler这个接口来实现一个同步(Synchronous)处理用户请求的类。比如你希望对于一切类型为fakephp的请求都通过你的Http Hanlder来处理,你可以实现以下这个类:

 

using System; using System.Web; public class FakePHPHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { //let's pretend we can handle PHP stuff } public bool IsReusable { get { return true; } } }

然后通过在IIS里将你的dll注册为.fakephp的handler就可以了。这些在以下的MSDN文档里都有介绍:

http://msdn2.microsoft.com/en-us/library/system.web.ihttphandler.aspx

 

这里想说的是如何实现一个异步(Asynchronous)d的HTTP Handler。说起来其实也简单,只要实现IHttpAsyncHandler这个接口就好了。

IHttpAsyncHandler有两个method:

 

Public method BeginProcessRequest
Initiates an asynchronous call to the HTTP handler.

Public method EndProcessRequest
Provides an asynchronous process End method when the process ends.

这显然是和.NET Framework中标准的Asynchronous Programming Model (或者叫“异步模式”, Asynchronous Pattern)是一致的:

参考: Asynchronous Programming Overview

异步模式的优势是ASP.NET的worker thread不会等待BeginProcessRequest返回而是会掉头去接收其他的用户请求(当然你也可以要求worker thread等待,不过这样就等于变成了Synchronous Handler)。因为通常处理一个web request的后台时间需要比较长。假设你每秒只能处理10个用户请求,在同步模式下如果有11个人同时访问你的服务,就有一个人会看到500 Internal Server Error之类的错误消息了。但如果是异步模式,worker thread只要调用BeginProcessRequest,而根据Asynchronous Programming Overview,BeginProcessRequest应该立刻返回(“立刻”的含义是它不应该进行长时间的操作,而应该调用QueueUserWorkItem之类的API将耗时的任务放到新线程里执行),这样worker thread就可以腾出手去接收下一个user request了。

注:ASP.NET的max worker thread上限可以通过processModel configuration element里的maxWorkerThreads属性来改变(参考:Improving ASP.NET Performance 以及 processModel element),但最大的值也只是100 (range from 5 to 100, default 20)。

由此引出的问题自然是:当异步操作完成时, ASP.NET是如何知道并做相应处理的。这有一下几种选择:

1) 当调用BeginProcessRequest的时候,ASP.NET可以同时传入一个AsyncCallback的delegate,而在你完成异步操作后,你应该调用这个回调函数来通知ASP.NET。

2) ASP.NET可以不停地查看IAsyncResult (这个是BeginProcessRequest的返回值)IsCompleted属性来确认异步操作是否已经完成了,当然,当你完成异步操作时,你有义务将IsCompleted设成true。

3) ASP.NET也可以等待AsyncWaitHandle的信号,AsyncWaitHandle是IAsyncResult的另一个属性,这个和经典的Win32里waiting on kernel object是类似的。

4) ASP.NET可以直接调用EndProcessRequest。

注意:3) 和 4) 是Asynchronous Programming Overview里规定的标准的blocking execution的方式,也就是说,如果你的主线程在异步操作完成前无法再做任何工作时,它可以通过3) 或者 4)来等待异步操作的完成。

从理论上来说,你应该保证你的IHttpAsyncHandler能满足以上所有4种方式。但现实中,你未必一定如此做。那么哪些是我们必须实现以匹配ASP.NET的要求的呢?或者ASP.NET究竟是如何实现异步调用及返回的呢?

事实上,ASP.NET采用了方法1,也就是说,在调用BeignProcessRequest的时候,ASP.NET传入了一个AsyncCallback,而你应该在完成异步操作后调用这个callback,而在这个AsyncCallback里,ASP.NET又调用了你的EndProcessRequest来做收尾工作。

根据上面的讨论,我们可以如下设计我们的Asynchronous Http Hanlder:

 

public class AsyncFakePHPHttpHandler : IHttpAsyncHandler { private void ProcessRequestCallback(object state) { AsyncResult async = (AsyncResult)state; // this is where the real work is done ProcessRequest(async.context); async.isCompleted = true; if (null != async.asyncCallback) async.asyncCallback(async); } public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback asyncCallback, object state) { AsyncResult async = new AsyncResult(context, asyncCallback, state); // if the callback is null, we can return immediately and let EndProcessRequest do all the job // if callback is not null, we will use our thread pool to execute the necessary asynchronous operations // what happens in ASP.NET is that the callback in NOT null, so QueueUserWorkItem will be used if (null != async.asyncCallback) threadPool.QueueUserWorkItem(ProcessRequestCallback, async); return async; } // this design also satisfies method 4), we implement it this way to follow the Asynchronous Pattern as much as we can public void EndProcessRequest(IAsyncResult result) { AsyncResult async = (AsyncResult)result; if (null == async.asyncCallback) ProcessRequest(async.context); } }

 

总结一下实现异步Http Handler的要点:

1) 所有在BeginProcessRequest中的耗时操作(比如IO什么的)都应该采用异步调用(比如BeginRead/EndRead)或者生成新的线程去执行。不错,你可以设计一个blocking BeginProcessRequest,没有人能阻止你这么做。But that's a BAD BAD idea.

2) 实现BeginProcessRequest/EndProcessRequest的目的是允许ASP.NET来异步调用你的Http Handler

3) 你应该创建一个实现IAsyncResult接口的类,在BeginProcessRequest中你会生成一个该类的实例并返回给ASP.NET(注意BeginProcessRequest的返回值类型)。而根据Asynchronous Pattern,ASP.NET在调用EndProcessRequest的时候会把这个实例再传回给你,你可以用这个实例来判断你所执行的任务的当前状态。

4) 我个人感觉比较容易导致困惑的是这里“两段式”的异步调用操作。首先ASP.NET是通过BeginProcessRequest/EndProcessRequest来异步调用我们的Http Handler的。然后我们在BeginProcessRequest又再次用异步模式(用QueueUserWorkItem或者其他的Begin*/End*操作)去完成真正的工作。实际上第二步的异步调用才是真正生成另一个thread来处理工作的地方。ASP.NET调用我们的BeginProcessRequest只是一种形式上的协议通知,因为是我们告诉ASP.NET:Hey,我是一个异步的handler。ASP.NET说:那好吧,既然你这么说的,我就用你异步的接口来调用你。事实上,在HttpRuntime的源代码中,可以看到ASP.NET的操作如下:

                if (app is IHttpAsyncHandler) {
                    // asynchronous handler
                    IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
                    context.AsyncAppHandler = asyncHandler;
                    asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
                }
                else {
                    // synchronous handler
                    app.ProcessRequest(context);
                    FinishRequest(context.WorkerRequest, context, null);
                }

====================================================================

最后的题外话,关于IIS/ASP.NET处理请求的工作流也是一个很有趣的问题,下面的这篇文章很棒(but the author's English writing kinda sucks, : ) )。比如,从中我们可以知道,整个流程中其实牵涉了两个Queue,一个是Kernel mode下的,一个是User mode下的,而后者就是ASP.NET所使用的Application Queue,而ASP.NET的worker thread就是从这个Queue里去取下一个需要处理的请求的。

Dissection of an ASP.NET 2.0 request processing flow

打印 | 张贴于 2007-11-14 06:50:00 | Tag:暂无标签

留言反馈

#回复: ASP.NET异步请求处理(Asynchronous Http Handlers) 编辑
楼主,请说明白点

async.context,我的怎么没有 Context 这个属性.
2007-12-12 15:26:00 | [匿名:里奥特]
#回复: ASP.NET异步请求处理(Asynchronous Http Handlers) 编辑
很高兴能有所帮助,: ) 我尽量想把我自己的理解解释清楚,但也确实觉得其中还可能有比较模糊的内容。如果有什么疑问的话请尽管提出来。
2007-11-15 07:52:00 | [匿名:DemonFox]
#回复: ASP.NET异步请求处理(Asynchronous Http Handlers) 编辑
真神奇~这两天正好在研究这个玩意……四处问人都没有啥米结果,居然就这么看到这篇blog……

偶看的 http://msdn.microsoft.com/msdnmag/issues/03/06/threading/default.aspx

这篇东西……猜想就是ahnan说的msdn介绍文章吧?呵呵,这篇东西的确看得偶很糊涂~
2007-11-14 23:34:00 | [匿名:Wuvist]
#回复: ASP.NET异步请求处理(Asynchronous Http Handlers) 编辑
so清晰,比某次msdn上的介绍文章清楚多了. Thanks!
2007-11-14 17:11:00 | [匿名:ahnan]

发表留言

标题
姓名
邮件
主页
留言 

Powered by: Joycode.MVC引擎 0.5.2.0