为什么我的请求由spray-http中的单个线程处理? [英] Why are my requests handled by a single thread in spray-http?

查看:96
本文介绍了为什么我的请求由spray-http中的单个线程处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Spray-can,spray-http 1.3.2和akka 2.3.6设置了http服务器。
我的application.conf没有任何akka(或喷雾)条目。我的演员代码:

I set up an http server using spray-can, spray-http 1.3.2 and akka 2.3.6. my application.conf doesn't have any akka (or spray) entries. My actor code:

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​​的日志记录配置,以免影响结果),但所有操作均由同一线程处理,该线程处于休眠状态,并且只有在唤醒后才拾取下一个请求。

When I send 10 concurrent requests, they are all accepted immediately by spray and forwarded to different dispatcher actors (according to logging config for akka I have removed from applicaiton.conf lest it influenced the result), but all are handled by the same thread, which sleeps, and only after waking up picks up the next request.

我应该在配置中添加/更改什么?根据我在reference.conf中看到的内容,默认执行程序是fork-join-executor,所以我希望所有请求都可以在开箱即用的条件下并行执行。

What should I add/change in the configuration? From what I've seen in reference.conf the default executor is a fork-join-executor, so I'd expect all the requests to execute in parallel out of the box.

推荐答案

从您的代码中,我看到只有一个 TestActor 可以处理所有请求,因为您只创建了一个 system.actorOf 。您知道, actorOf 不会为每个请求创建新的actor-除此之外,您还有 val ,因此它只是一个演员。这个角色依次处理请求,并且您的路由正在该角色内部进行处理。调度程序没有理由选择另一个线程,而每次仅一个线程仅由一个参与者使用,因此日志中只有一个线程(但不能保证)-我认为这是第一个

From your code I see that there is only one TestActor to handle all requests, as you've created only one with system.actorOf. You know, actorOf doesn't create new actor per request - more than that, you have the val there, so it's only one actor. This actor handles requests sequntially one-by-one and your routes are processing inside this actor. There is no reason for dispatcher to pick-up some another thread, while the only one thread per time is used by only one actor, so you've got only one thread in the logs (but it's not guaranteed) - I assume it's first thread in the pool.

Fork-join执行器在这里什么也不做,除了给出第一个并且始终是相同的自由线程,因为不再有参与者需要与当前线程并行的线程。因此,它一次仅接收一项任务。即使发生窃取工作的情况,也无法正常工作,直到您有一些被阻塞(并标记为受管理的阻塞)线程来窃取资源。 Thread.sleep(1000)本身不会自动标记线程-您应该使用 scala.concurrent.blocking 以使用工作偷窃。无论如何,当您只有一个参与者时,它仍然只是一个线程。

Fork-join executor does nothing here except giving first and always same free thread as there is no more actors requiring threads in parallel with current one. So, it receives only one task at time. Even with "work stealing" - it doesn't work til you have some blocked (and marked to have managed block) thread to "steal" resources from. Thread.sleep(1000) itself doesn't mark thread automatically - you should surround it with scala.concurrent.blocking to use "work stealing". Anyway, it still be only one thread while you have only one actor.

如果您需要多个参与者来处理请求-只需传递一些 akka路由器演员(与Spray-Router路由器没有任何共同之处):

If you need to have several actors to process the requests - just pass some akka router actor (it has nothing in common with spray-router):

val restService = context.actorOf(RoundRobinPool(5).props(Props[TestActor]), "router")  

这将创建一个由5个参与者组成的池(不是线程池)来满足您的请求。

That will create a pool (not thread-pool) with 5 actors to serve your requests.

这篇关于为什么我的请求由spray-http中的单个线程处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆