为什么我的异步控制器会阻塞?

时间:2017-06-22 01:00:44

标签: scala playframework concurrency

我是新手一般玩框架和scala。在尝试测试和理解同步和异步操作之间的差异时,使用以下代码:

package controllers

import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._
import scala.concurrent.Future

object Application extends Controller {

  def async = Action.async {
    Logger.info("async start")
    val resultF = Future {
      Thread.sleep(2000)
      Logger.info("async end")
      Ok
    }
    Logger.info("non-blocking")
    resultF
  }

  def sync = Action {
    Thread.sleep(2000)
    Ok
  }

}

运行应用程序时,我在浏览器中有10个选项卡请求" / async"。我的期望是所有请求都需要大约2秒才能完成填充,我会在日志中看到10" async start"条目后跟10" async end"条目。

然而,实际结果是看到" async start"," async end" 10倍。在上一个请求完成之前,下一个请求才开始。似乎async的执行是阻塞的,根本无法处理并发请求。

我的问题是为什么系统会以这种方式运行,以及启用并发请求处理的具体更改。

2 个答案:

答案 0 :(得分:2)

使用Action.async并不会自动表示您没有阻止。这完全取决于您是否使用阻止API。

Thread.sleepFuture中的阻止操作,但您没有向ExecutionContext发信号通知您正在这样做,因此行为将根据ExecutionContext的不同而有所不同您使用和您的机器有多少处理器。您的代码按预期使用ExecutionContext.global

在这两种情况下,您使用Thread.sleep(2000)阻止线程。

在这两种情况下,睡眠调用都发生在动作的线程池中(这不是最佳的)。

如了解Play Play线程池中所述:

  

Play框架是自下而上的异步Web框架。使用迭代器异步处理流。 Play中的线程池被调整为使用比传统Web框架更少的线程,因为play-core中的IO永远不会阻塞。

     

因此,如果您计划编写阻塞IO代码或可能会执行大量CPU密集型工作的代码,则需要确切地知道哪个线程池承载了该工作负载,并且您需要相应地对其进行调整。

在你的情况下,你只是在两个阻塞线程的情况下等待几秒钟,其中并行因子的默认设置是1。

如果您要阻止该主题,可以使用以下内容:

 def async = Action.async {
    Logger.info("async start")
    val resultF = Future {
      blocking{
        Thread.sleep(2000)
        Logger.info("async end")
        Ok
      }
    }
    Logger.info("non-blocking")
    resultF
  }

答案 1 :(得分:0)

代码工作正常。

使用ab(ApacheBench)或其他方式发送并发请求。

> ab -c 5 -n 5 localhost:9000/async
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software:        
Server Hostname:        localhost
Server Port:            9000

Document Path:          /async
Document Length:        0 bytes

Concurrency Level:      5
Time taken for tests:   2.013 seconds
Complete requests:      5
Failed requests:        0
Total transferred:      375 bytes
HTML transferred:       0 bytes
Requests per second:    2.48 [#/sec] (mean)
Time per request:       2013.217 [ms] (mean)
Time per request:       402.643 [ms] (mean, across all concurrent requests)
Transfer rate:          0.18 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:  2008 2011   2.0   2011    2013
Waiting:     2007 2011   2.0   2011    2013
Total:       2008 2011   2.0   2011    2013

Percentage of the requests served within a certain time (ms)
  50%   2011
  66%   2012
  75%   2012
  80%   2013
  90%   2013
  95%   2013
  98%   2013
  99%   2013
 100%   2013 (longest request)

我发送了5个并发请求,所有请求都按预期结束(参见上面的Time taken for tests: 2.013 seconds