Play Framework2.1的基本设计思想是可以快速处理大量耗时较少的请求,比较耗时的请求采用异步方式完成。为了很好地说明这一点,让咱们来看一个例子,编写控制器代码以下: java
public static AtomicInteger count = new AtomicInteger(0); public static Result test(Long id) { if(id!=0){ try { System.out.println("sleeping...:"+count.addAndGet(1)); Thread.currentThread().sleep(1000000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println("no sleep"); } return ok("good."); }在conf/routes文件中添加以下路由:
GET /:id controllers.Application.test(id:Long)执行play run启动项目,下面咱们打开浏览器进行测试。测试地址以下:
http://localhost:9000/1 - http://localhost:9000/9
须要注意的是,全部的请求须要在浏览器的一个窗口中完成,具体缘由请见下面的【说明】。控制台消息以下: 数据库
能够看出,在咱们发送第9次请求时,服务器报了error,错误缘由是“AskTimeoutException”,请求actor超时。 浏览器
【说明】 服务器
在上面的测试中,要求全部请求须要在一个浏览器窗口中完成,主要是由于各个版本的浏览器针对同一个域,有最大链接数限制,例如IE六、IE8和Chrome21的链接数以下: 架构
Chrome21的最大链接数:6 IE8的最大链接数:6 IE6的最大链接数:2这意味在访问下一个页面时,须要将以前的页面关掉,不然在Chrome21中,当打开第7个选项卡访问页面时,前面6个选项卡Chrome提示“正在等待响应”, 而第7个选项卡Chrome提示“正在发送请求”,这是由于前面的6个选项卡已经占满了6个链接,第7个选项卡只能等待前面的链接释放。
从上面的实验结果,能够观察到,默认状况下Play2.1只能同时处理8个耗时请求,在这个8个耗时请求未结束以前,第9个请求将会在默认的等待时间(1秒)结束后,报”500服务器内部错误“。 并发
须要说明的是,Play2.1的默认配置已经可以知足大部分小型应用的须要了。但在面对数据/计算密集型的应用,或是高并发的应用,默认的配置就显的力不从心了。本文主要从两方面来提升Play2.1的性能,一方面是提升请求处理的并发数;另外一方面,仅仅提升处理请求的并发数,在高并发状况下(如压力测试)仍然会处理“AskTimeoutException”,因此要提升这个等待时间。 app
在个人上一篇文章《Play Framework2.1源码分析 - 架构设计及线程策略分析》介绍了,在Play2.x中,实际处理请求的执行环境是AKKA的actors,而执行actors的线程资源是由跟actor相关联的dispatcher管理的。在Play2.1中,全部的AKKA actors都使用默认的default-dispatcher,其默认配置以下: 异步
play { akka { actor { retrieveBodyParserTimeout = 1 second default-dispatcher = { fork-join-executor { parallelism-min = 8 parallelism-factor = 1.0 parallelism-max = 24 } } } } }
其中retrieveBodyParserTimeout参数值的是,若是没有可用的actor处理请求,则默认等待1s,若是尚未则报500错误。接下来的三个参数parallelism-min、parallelism-factor和parallelism-max,就是具体的线程池配置了。parallelism-min和parallelism-max参数指明最小和最大线程数分别是8和24,parallelism-factor是线程池大小的计算因子。 看到min和max,相信不少人第一时间会联想到数据库链接池的配置,须要注意的是,这里的min和max的含义和数据库链接池的含义彻底不一样,只是做为最终计算结果的一个参考比较。下面说明一下线程池大小计算的具体过程: 高并发
- 首先计算parallelism-factor*processors, 其中processors为CPU的总核数,例如对于i5处理器,processors大小为4 源码分析
- 若是parallelism-factor*processors计算结果小于parallelism-min,则线程池大小为parallelism-min
- 若是parallelism-factor*processors计算结果大于parallelism-max,则线程池大小为parallelism-max
咱们看到,parallelism-min和parallelism-max参数只是起到校订parallelism-factor*processors计算结果的做用。
好了,经过上面的介绍,我想你应该知道怎么作了,这里给一个示例,把下面这部分配置追加到con/application.conf文件的尾部。下面的参数书写方式和自动生成的不太同样,不用担忧,Play支持多种书写方式,例如点式“db.default.user=sa”和下面这种相似JSON的方式,具体请参考官方文档,
play { akka { actor { retrieveBodyParserTimeout = 5 second default-dispatcher = { fork-join-executor { parallelism-min = 10 parallelism-factor = 100 parallelism-max = 100 } } } } }