Scala Play framework 2.0控制器/异步究竟是如何工作的?

Scala Play framework 2.0控制器/异步究竟是如何工作的?,scala,playframework-2.0,akka,evented-io,Scala,Playframework 2.0,Akka,Evented Io,我最近转到了PlayFramework2.0,关于控制器在游戏中的实际工作方式,有一些问题与我有关 其中提到: 由于Play2.0的工作方式,动作代码必须尽可能快 可能(即非阻塞) 但在以下方面: 及 似乎有24个参与者分配给控制器处理。我猜每个请求都会在请求的生命周期中分配一个参与者是这样吗? 另外,parallelism factor是什么意思,fork-join-executor与thread-pool有何不同 另外,文档应该说明异步应该用于长时间的计算什么算长?100毫秒?300毫秒?5

我最近转到了PlayFramework2.0,关于控制器在游戏中的实际工作方式,有一些问题与我有关

其中提到:

由于Play2.0的工作方式,动作代码必须尽可能快 可能(即非阻塞)

但在以下方面:

似乎有24个参与者分配给控制器处理。我猜每个请求都会在请求的生命周期中分配一个参与者是这样吗?

另外,
parallelism factor
是什么意思,
fork-join-executor
thread-pool
有何不同

另外,文档应该说明异步应该用于长时间的计算什么算长?100毫秒?300毫秒?5秒?10秒?我猜一秒钟内什么都可以,但如何确定呢

这个问题的原因是测试异步控制器调用比常规调用困难得多。您必须启动一个伪应用程序并执行一个完整的请求,而不是仅仅调用一个方法并检查其返回值

即使不是这样,我也怀疑用
Async
Akka.future
来包装一切是正确的做法

我在#playframework IRC频道上问过这个问题,但没有人回答,似乎我不是唯一一个不确定应该如何做的人

我只想重申:

  • 每个请求从/actions池中分配一个参与者是否正确
  • 并行系数是什么意思?为什么是1
  • fork join executor
    线程池executor
    有何不同
  • 一个计算在
    Async
    中包装需要多长时间
  • 在不启动虚假应用程序的情况下测试异步控制器方法是不可能的吗
  • 提前谢谢

    编辑:一些来自IRC的内容

    一些来自IRC的东西

    <imeredith> arturaz: i cant be boethered writing up a full reply but here are key points
    <imeredith> arturaz: i believe that some type of CPS goes on with async stuff which frees up request threads
    <arturaz> CPS?
    <imeredith> continuations
    <imeredith> when the future is finished, or timedout, it then resumes the request
    <imeredith> and returns data
    <imeredith> arturaz: as for testing, you can do .await on the future and it will block until the data is ready
    <imeredith> (i believe)
    <imeredith> arturaz: as for "long" and parallelism - the longer you hold a request thread, the more parrellism you need
    <imeredith> arturaz: ie servlets typically need a lot of threads because you have to hold the request thread open for a longer time then if you are using play async
    <imeredith> "Is it right that every request allocates one actor from /actions pool?" - yes i belive so
    <imeredith> "What does parallelism-factor mean and why is it 1?" - im guessing this is how many actors there are in the pool?
    <imeredith> or not
    <imeredith> "How does fork-join-executor differ from thread-pool-executor?" -no idea
    <imeredith> "How long should a calculation be to become wrapped in Async?" - i think that is the same as asking "how long is a piece of string"
    <imeredith> "Is is not possible to test async controller method without spinning up fake applications?" i think you should be able to get the result
    <viktorklang> imeredith: A good idea is to read the documentation: http://doc.akka.io/docs/akka/2.0.3/general/configuration.html ( which says parallelism-factor is: # Parallelism (threads) ... ceil(available processors * factor))
    <arturaz> viktorklang, don't get me wrong, but that's the problem - this is not documentation, it's a reminder to yourself.
    <arturaz> I have absolutely no idea what that should mean
    <viktorklang> arturaz: It's the number of processors available multiplied with the factor you give, and then rounded up using "ceil". I don't know how it could be more clear.
    <arturaz> viktorklang, how about: This factor is used in calculation `ceil(number of processors * factor)` which describes how big is a thread pool given for your actors.
    <viktorklang> arturaz: But that is not strictly true since the size is also guarded by your min and max values
    <arturaz> then why is it there? :)
    <viktorklang> arturaz: Parallelism (threads) ... ceil(available processors * factor) could be expanded by adding a big of conversational fluff: Parallelism ( in other words: number of threads), it is calculated using the given factor as: ceil(available processors * factor)
    <viktorklang> arturaz: Because your program might not work with a parallelism less than X and you don't want to use more threads than X (i.e if you have a 48 core box and you have 4.0 as factor that'll be a crapload of threads)
    <viktorklang> arturaz: I.e. scheduling overhead gives diminishing returns, especially if ctz switching is across physical slots.
    <viktorklang> arturaz: Changing thread pool sizes will always require you to have at least basic understanding on Threads and thread scheduling
    <viktorklang> arturaz: makes sense?
    <arturaz> yes
    <arturaz> and thank you
    <arturaz> I'll add this to my question, but this kind of knowledge would be awesome docs ;)
    
    arturaz:我写不出一个完整的答复,但这里有几个要点
    arturaz:我相信某种类型的CPS会继续使用异步的东西来释放请求线程
    CPS?
    延续
    当future或timedout完成时,它会恢复请求
    并返回数据
    阿图拉兹:至于测试,你可以这样做。等待未来,它将阻止,直到数据准备就绪
    (我相信)
    arturaz:至于“长”和并行性——你持有请求线程的时间越长,你需要的并行性就越多
    arturaz:ie Servlet通常需要很多线程,因为如果使用play async,则必须将请求线程保持在打开状态更长的时间
    “每个请求从/actions池中分配一个参与者是否正确?”-是的,我相信是这样
    “平行度因子是什么意思?为什么是1?”-我猜这就是池中有多少演员?
    还是不
    “fork join executor和线程池executor有何不同?”-不知道
    “一个计算应该在异步中包装多长时间?”-我认为这与问“一段字符串有多长”是一样的
    “在不旋转虚假应用程序的情况下测试异步控制器方法是不可能的吗?”我认为您应该能够得到结果
    imeredith:一个好主意是阅读文档:http://doc.akka.io/docs/akka/2.0.3/general/configuration.html (表示并行度因子为:#并行度(线程)…ceil(可用处理器*因子))
    viktorklang,别误会我的意思,但这就是问题所在——这不是文档,而是提醒你自己。
    我完全不知道那意味着什么
    arturaz:可用处理器的数量乘以你给出的因子,然后用“ceil”四舍五入。我不知道怎样才能更清楚。
    viktorklang,怎么样:这个因子用于计算‘ceil(处理器数量*因子)’,它描述了为参与者提供的线程池有多大。
    阿图拉兹:但这并不是严格正确的,因为大小也由最小值和最大值保护
    那为什么会在那里呢?:)
    arturaz:并行性(线程)。。。ceil(可用处理器*因子)可以通过添加大量会话绒毛来扩展:并行性(换句话说:线程数),它是使用给定的因子计算的:ceil(可用处理器*因子)
    arturaz:因为您的程序可能无法使用小于X的并行度,并且您不希望使用比X更多的线程(即,如果您有一个48核的机箱,并且您有4.0作为因子,那么将是一个线程负载)
    arturaz:也就是说,调度开销带来的回报是递减的,特别是当ctz切换跨越物理插槽时。
    arturaz:更改线程池大小始终要求您至少对线程和线程调度有基本的了解
    阿图拉兹:有道理吗?
    对
    谢谢你
    我会在我的问题中添加这一点,但这种知识将非常棒;)
    
  • 当一条消息到达一个参与者时,它会抓住该参与者,直到处理该消息为止。如果同步处理请求(在处理该消息期间计算整个响应),则在响应完成之前,该参与者无法为其他请求提供服务。相反,如果您可以在收到此请求后将工作发送给另一个参与者,则收到请求的参与者可以在其他参与者处理第一个请求时开始处理下一个请求

  • 用于参与者的线程数为“num CPU*并行度因子”(但可以指定最小值和最大值)

  • 不知道

  • 除非有真正的计算在进行,否则我倾向于使任何与其他系统对话的东西都异步,比如用数据库/文件系统执行io。当然,任何可能阻塞线程的东西。然而,由于传递消息的开销很小,我认为只发送所有消息不会有问题
            actions-dispatcher = {
                fork-join-executor {
                    parallelism-factor = 1.0
                    parallelism-max = 24
                }
            }
    
    <imeredith> arturaz: i cant be boethered writing up a full reply but here are key points
    <imeredith> arturaz: i believe that some type of CPS goes on with async stuff which frees up request threads
    <arturaz> CPS?
    <imeredith> continuations
    <imeredith> when the future is finished, or timedout, it then resumes the request
    <imeredith> and returns data
    <imeredith> arturaz: as for testing, you can do .await on the future and it will block until the data is ready
    <imeredith> (i believe)
    <imeredith> arturaz: as for "long" and parallelism - the longer you hold a request thread, the more parrellism you need
    <imeredith> arturaz: ie servlets typically need a lot of threads because you have to hold the request thread open for a longer time then if you are using play async
    <imeredith> "Is it right that every request allocates one actor from /actions pool?" - yes i belive so
    <imeredith> "What does parallelism-factor mean and why is it 1?" - im guessing this is how many actors there are in the pool?
    <imeredith> or not
    <imeredith> "How does fork-join-executor differ from thread-pool-executor?" -no idea
    <imeredith> "How long should a calculation be to become wrapped in Async?" - i think that is the same as asking "how long is a piece of string"
    <imeredith> "Is is not possible to test async controller method without spinning up fake applications?" i think you should be able to get the result
    <viktorklang> imeredith: A good idea is to read the documentation: http://doc.akka.io/docs/akka/2.0.3/general/configuration.html ( which says parallelism-factor is: # Parallelism (threads) ... ceil(available processors * factor))
    <arturaz> viktorklang, don't get me wrong, but that's the problem - this is not documentation, it's a reminder to yourself.
    <arturaz> I have absolutely no idea what that should mean
    <viktorklang> arturaz: It's the number of processors available multiplied with the factor you give, and then rounded up using "ceil". I don't know how it could be more clear.
    <arturaz> viktorklang, how about: This factor is used in calculation `ceil(number of processors * factor)` which describes how big is a thread pool given for your actors.
    <viktorklang> arturaz: But that is not strictly true since the size is also guarded by your min and max values
    <arturaz> then why is it there? :)
    <viktorklang> arturaz: Parallelism (threads) ... ceil(available processors * factor) could be expanded by adding a big of conversational fluff: Parallelism ( in other words: number of threads), it is calculated using the given factor as: ceil(available processors * factor)
    <viktorklang> arturaz: Because your program might not work with a parallelism less than X and you don't want to use more threads than X (i.e if you have a 48 core box and you have 4.0 as factor that'll be a crapload of threads)
    <viktorklang> arturaz: I.e. scheduling overhead gives diminishing returns, especially if ctz switching is across physical slots.
    <viktorklang> arturaz: Changing thread pool sizes will always require you to have at least basic understanding on Threads and thread scheduling
    <viktorklang> arturaz: makes sense?
    <arturaz> yes
    <arturaz> and thank you
    <arturaz> I'll add this to my question, but this kind of knowledge would be awesome docs ;)
    
    object ControllerHelpers {
      class ResultExtensions(result: Result) {
        /**
         * Retrieve Promise[Result] from AsyncResult
         * @return
         */
        def asyncResult = result match {
          case async: AsyncResult => async.result
          case _ => throw new IllegalArgumentException(
            "%s of type %s is not AsyncResult!".format(result, result.getClass)
          )
        }
    
        /**
         * Block until result is available.
         *
         * @return
         */
        def await = asyncResult.await
    
        /**
         * Block until result is available.
         *
         * @param timeout
         * @return
         */
        def await(timeout: Long) = asyncResult.await(timeout)
    
        /**
         * Block for max 5 seconds to retrieve result.
         * @return
         */
        def get = await.get
      }
    }
    
      implicit def extendResult(result: Result) =
        new ControllerHelpers.ResultExtensions(result)
    
    
      val result = c.postcodeTimesCsv()(request(params)).get
      status(result) should be === OK