看过Servlet 3.0的规范和API后,可以看出来,所谓异步的HTTP,其实异步的不是HTTP,而是服务器端异步地处理HTTP请求,而HTTP客户端,仍旧是同步的等待服务端的处理结果。一般servlet容器会分配一个线程用来处理一个来自客户端的HTTP请求,在这个线程发送回HTTP响应之前,这个线程只属于这个HTTP请求不能离开处理其它请求。采用Servlet3.0之后,当前的线程可以开启异步处理,开启异步处理的时候会得到一个异步处理上下文对象,之后当前的线程就可以不生成HTTP响应而直接退出去处理其它的HTTP请求,其它线程可以在之后通过异步处理上下文来生成和发送那个HTTP响应。可见所谓的异步HTTP其实只是一种可以让当前的处理线程在不生成响应前就离开,而在之后再处理这个HTTP请求的机制。
从客户端看来,不论是哪种方式,浏览器都在发送完HTTP请求之后,都必须同步的等待服务器端的响应。假如浏览器发送完HTTP请求之后,可以在得到服务器处理结果之前转而处理其它事情,而在未来的某个时刻,当服务器处理完请求后,不需要客户端再发送请求,就可以发响应发回给浏览器,也许那才是真的异步HTTP了。但是这是违反HTTP的有请求才响应,无请求不响应的基本原则的。 HTTP长连接可以让客户端和服务器在同一个TCP连接中做多次请求响应,但是并不能改变客户端和服务器之间的同步请求响应模式。
尽管Servlet3.0的异步功能不能改变HTTP的协议,在本质上让浏览器和服务器之间异步的交互,但是这一功能还是有非常大的意义的。假设接受请求和发送响应的时间分别为Req和Resp,每个请求都要执行一个耗时P的操作O,并且O操作会让调用者阻塞,当在P时间内有n个请求发送过来时,用传统的处理方式,由于P时间内每个线程都不能处理完,servlet容器要分配F(n) = n个线程处理请求,如下图所示:
而用Servlet3.0的异步处理时,处理线程可以开启单一线程去做那个耗时P的操作,而把当前请求的异步处理上下文放入一个等待队列中,自己则接着处理其它的请求,假设这个开启异步,加入异步处理上下文的操作需要时间A,那么需要开启F(n) = n*(A+Req+Resp)/(P + Req + Resp) + 1个线程就可以在P时间内处理完所有请求。如下图所示:
假如执行操作O可以不阻塞,耗时C就返回, 那么n客户端每获得一次资源,需要发送f(n) = n*P / (Req + C + Resp) 次请求,而用异步处理的时候,只需要n次请求。可见当A足够小于P时,O阻塞访问时,异步可以用更少的线程处理更多的请求;O非阻塞访问时,异步可以减少请求次数。
以web QQ为例来看看。用户发送消息时,假设服务器分发消息耗时P远远大于开启异步和把消息放到待分发队列的耗时A,那么采用异步处理发送消息,可以用更少的线程处理更多的发送消息请求。用户接受消息,假设平均P时间内用户才有新消息到达,而检查一次新消息的耗时远小于P,那么采用异步则可以减少很多客户端请求。
没有相关文章
“每个请求都要执行一个耗时P的操作O,并且O操作会让调用者阻塞,” 很抱歉我对这句话没有完全理解,什么是P?什么是O?
“Servlet3.0的异步处理时,处理线程可以开启单一线程去做那个耗时P的操作” 对这个句话也不理解? 处理什么线程?哪来的线程需要被处理? 我的理解能力不够好,请多多见谅,呵呵。
说真的,我又看了2遍,作为一个初学者的角度 还真的不能完全听明白您的上述道白,sorry…..
PS:
1.如果说理论、底层的东西就尽量去白话,多打比方,少点数学公式。
2.太多字,不如一张图,一图抵千字。
这两天比较忙,匆忙写的,有些地方是不太好说清楚。确实是上图方便,改天加上。
类似完成端口?
不太明白你所谓的端口是指什么
O是指一个耗时比较长的操作,比如访问数据库等。P是指完成O这个操作需要使用的时间。
处理线程指的是当前的处理http请求的线程,这是个定语。
图不太好画,不过我还是画了个图上去了。数学公式也不是精确地表达,但是从一定程度上可以看出什么各种量之间的关系,我觉得更易于理解。如果只说使用了异步,可以处理更多并发的客户端请求,很多人可能不清楚为什么,以及在多大程度上处理更多的请求,有了公式就容易理解一点。
大部分赞同,虽然我没有看过servlet3.0规范。但我想图上那个异步执行只有一个线程的方式应该是你的例子,而不是servlete容器真正的模型。否则所有的业务都交由一个线程处理,无法利用多CPU或者多核的能力。应该是交由一个线程池来处理才对。
这种模型的一个优点是可以提高接受请求的数量。因为有一些线程专门负责接受请求,只负责接受请求。
谢谢你的回复。你说的是很有道理的,如果要处理的操作,可以并发,瓶颈在CPU的话,是可以像你说的那样的。如果要处理的操作不可以并发,或者瓶颈并不在CPU上,用多个线程来处理的意义也不大,因为这多个线程还是会阻塞住。