为什么我的请求由spray-http中的单个线程处理?

时间:2015-03-05 17:42:54

标签: akka spray

我使用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,所以我希望所有请求都是开箱即用的。

1 个答案:

答案 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个演员的池(不是线程池)来满足您的请求。