我使用spray-can,spray-http 1.3.2和akka 2.3.6设置了一个http服务器。 我的application.conf没有任何akka(或spray)条目。我的演员代码:
class TestActor extends HttpServiceActor with ActorLogging with PlayJsonSupport {
val route = get {
path("clientapi"/"orders") {
complete {{
log.info("handling request")
System.err.println("sleeping "+Thread.currentThread().getName)
Thread.sleep(1000)
System.err.println("woke up "+Thread.currentThread().getName)
Seq[Int]()
}}
}
}
override def receive: Receive = runRoute(route)
}
像这样开始:
val restService = system.actorOf(Props(classOf[TestActor]), "rest-clientapi")
IO(Http) ! Http.Bind(restService, serviceHost, servicePort)
当我发送10个并发请求时,它们都被喷射立即接受并转发给不同的调度员(根据我从applicaiton.conf中删除的akka的日志配置,以免影响结果),但所有都由睡觉的同一个线程,只有在醒来之后才会收到下一个请求。
我应该在配置中添加/更改什么?根据我在reference.conf中看到的,默认执行程序是fork-join-executor,所以我希望所有请求都是开箱即用的。
答案 0 :(得分:9)
从您的代码中我发现只有一个TestActor
来处理所有请求,因为您只创建了一个system.actorOf
。你知道,actorOf
并没有为每个请求创建新的演员 - 更重要的是,你有val
,所以它只有一个演员。这个actor一个接一个地处理请求,你的路由正在这个actor中处理。调度员没有理由接收另一个线程,而每次只有一个线程只由一个actor使用,所以你在日志中只有一个线程(但是它不能得到保证) ) - 我认为它是游泳池中的第一个线程。
Fork-join执行器在此处不执行任何操作,除了给出第一个和始终相同的自由线程,因为没有更多的actor需要与当前线程并行的线程。因此,它只接收一个任务。即使是"偷工作" - 它没有工作直到你有一些被阻止(并标记为有管理块)线程到"窃取"来自的资源。 Thread.sleep(1000)
本身并不会自动标记线程 - 您应该使用scala.concurrent.blocking
将其包围起来以使用"工作窃取"。无论如何,当你只有一个演员时,它仍然只是一个线程。
如果你需要有几个演员来处理请求 - 只需传递一些akka router actor(它与spray-router没有任何共同之处):
val restService = context.actorOf(RoundRobinPool(5).props(Props[TestActor]), "router")
这将创建一个包含5个演员的池(不是线程池)来满足您的请求。