我在线程池服务阻止请求中有一个线程。
def sync = Action {
import Contexts.blockingPool
Future {
Thread.sleep(100)
}
Ok("Done")
}
在Contexts.blockingPool中配置为:
custom-pool {
fork-join-executor {
parallelism-min = 1
parallelism-max = 1
}
}
从理论上讲,如果上述请求同时接收到100个请求,则预期的行为应该是:1个请求应该休眠(100),其余99个请求应该被拒绝(或排队直到超时?)。但是,我观察到创建了额外的工作线程来处理其余的请求。我还观察到,当池中的线程数小于接收到的请求时,延迟随着(变得慢于服务请求)而增加。
如果收到大于配置的线程池大小的请求,预期的行为是什么?
您的检验结构不正确,无法检验您的假设。如果您在文档中仔细阅读本节,将会看到Play具有一些线程池/执行上下文。关于您的问题,最重要的一个是默认线程池以及它与您的操作所服务的HTTP请求之间的关系。
如文档所述,默认情况下,默认线程池是所有应用程序代码运行的地方。即,所有动作代码,包括所有动作代码Future
(未明确定义其自己的执行上下文),都将在此执行上下文/线程池中运行。因此,使用您的示例:
def sync = Action {
// *** import Contexts.blockingPool
// *** Future {
// *** Thread.sleep(100)
// ***}
Ok("Done")
}
您操作中所有未注释的代码// ***
将在默认线程池中运行。即当请求路由到您的操作时:
Future
一起Thread.sleep
将分派到您的自定义执行上下文Future
完成(因为它在自己的线程池[ Context.blockingPool
]中运行,因此不会阻塞默认线程池上的任何线程)Ok("Done")
陈述被评估,客户收到回复Future
完成了因此,为了解释您的观察,当您发送100个并发请求时,Play会很乐意接受这些请求,路由到您的控制器操作(在默认线程池上执行),分派给您Future
,然后响应客户端。
默认池的默认大小为
play {
akka {
...
actor {
default-dispatcher = {
fork-join-executor {
parallelism-factor = 1.0
parallelism-max = 24
}
}
}
}
}
每个内核最多使用24个线程。每个线程最多使用24个线程。考虑到您的操作几乎没有(不包括Future
),您将能够处理每秒1000个请求。你Future
会通过但积压工作更长的时间花费,因为你是在自定义池阻塞线程只有(blockingPool
)。
如果您使用我的操作略有调整的版本,您将在日志输出中看到确认上述说明的内容:
object Threading {
def sync = Action {
val defaultThreadPool = Thread.currentThread().getName;
import Contexts.blockingPool
Future {
val blockingPool = Thread.currentThread().getName;
Logger.debug(s"""\t>>> Done on thread: $blockingPool""")
Thread.sleep(100)
}
Logger.debug(s"""Done on thread: $defaultThreadPool""")
Results.Ok
}
}
object Contexts {
implicit val blockingPool: ExecutionContext = Akka.system.dispatchers.lookup("blocking-pool-context")
}
您的所有请求都将被快速处理,然后再Future
一个一个地完成。
因此,总而言之,如果您真的想测试Play如何仅用一个线程处理请求来处理许多并发请求,那么可以使用以下配置:
play {
akka {
akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
loglevel = WARNING
actor {
default-dispatcher = {
fork-join-executor {
parallelism-min = 1
parallelism-max = 1
}
}
}
}
}
您可能还想向操作中添加一个Thread.sleep
(这样可以降低默认线程池中的寂寞线程的速度)
...
Thread.sleep(100)
Logger.debug(s"""<<< Done on thread: $defaultThreadPool""")
Results.Ok
}
现在,您将拥有1个用于请求的线程和1个用于您Future
的线程。如果您以高并发连接数运行此程序,您会注意到客户端在Play一步一步地处理请求时阻塞。您期望看到的是...
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句