Как точно работают контроллеры Play Framework 2.0/Async? - программирование
Подтвердить что ты не робот

Как точно работают контроллеры Play Framework 2.0/Async?

Недавно я перешел в Play Framework 2.0, и есть некоторые вопросы, касающиеся меня относительно того, как контроллеры действительно работают в игре.

В играть в документы упоминаются:

Из-за того, как работает Play 2.0, код действия должен быть таким же быстрым, как возможно (без блокировки).

Однако в другой части документов:

            /actions {
                router = round-robin
                nr-of-instances = 24
            }

и

        actions-dispatcher = {
            fork-join-executor {
                parallelism-factor = 1.0
                parallelism-max = 24
            }
        }

Кажется, что для управления контроллерами имеется 24 участника. Я предполагаю, что каждый запрос выделяет одного из этих участников на всю жизнь запроса. Правильно ли это?

Кроме того, что означает parallelism-factor и как fork-join-executor отличается от thread-pool?

Также - документы должны сказать, что Async следует использовать для длинных вычислений. Что квалифицируется как длинный расчет? 100мс? 300мс? 5 секунд? 10 секунд? Мое предположение было бы чем-то более секунды, но как это определить?

Причина этого опроса заключается в том, что тестирование вызовов асинхронного контроллера намного сложнее обычных вызовов. Вам нужно развернуть поддельное приложение и выполнить полноценный запрос, а не просто вызвать метод и проверить его возвращаемое значение.

Даже если это не так, я сомневаюсь, что это все, что связано с Async и Akka.future.

Я попросил об этом в #playframework IRC-канале, но ответа не было, и похоже, что я не единственный, кто не уверен, как все должно быть сделано.

Просто повторю:

  • Правильно ли, что каждый запрос выделяет одного участника из пула действий/действий?
  • Что означает parallelism-factor и почему это 1?
  • Как fork-join-executor отличается от thread-pool-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 the problem - this is not documentation, it a reminder to yourself.
<arturaz> I have absolutely no idea what that should mean
<viktorklang> arturaz: It 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 ;)
4b9b3361

Ответ 1

  • Когда сообщение поступает на актера актера, он держится за этого актера до тех пор, пока он обрабатывает это сообщение. Если вы обрабатываете запрос синхронно (вычисляете весь ответ во время обработки этого сообщения), тогда этот субъект не может обслуживать другие запросы до тех пор, пока не будет выполнен ответ. Если вместо этого вы можете по получении этого запроса отправить работу другому актеру, актер, получивший запрос, может начать работу над следующим запросом, пока первый запрос обрабатывается другими участниками.

  • Число потоков, используемых для участников, это "num cpus * parallelism -factor" (вы можете указать min и max)

  • Незнайка

  • Если не будут выполнены реальные вычисления, я бы попытался сделать асинхронным все, что говорит с какой-либо другой системой, например, делать с базой данных/файловой системой. Конечно, все, что может заблокировать поток. Однако, поскольку в передаче сообщений слишком мало накладных расходов, я не думаю, что возникла бы проблема с отправкой всей работы другим игрокам.

  • См. Документация о воспроизведении функциональных тестов о том, как тестировать ваши контроллеры.

Ответ 2

Кажется, что вы можете сделать это для тестирования:

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