15

私は最近PlayFramework2.0に移行しましたが、コントローラーが実際にPlayでどのように機能するかについていくつか質問があります。

プレイドキュメントには次のように記載されています。

Play 2.0の動作方法により、アクションコードは可能な限り高速である必要があります(つまり、ノンブロッキング)。

ただし、ドキュメントの別の部分では

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

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

コントローラーの処理には24のアクターが割り当てられているようです。私は、すべてのリクエストが、リクエストの存続期間中、それらのアクターの1つを割り当てると思います。そうですか?

また、どういうparallelism-factor意味で、どうfork-join-executor違うのthread-poolですか?

また、ドキュメントには、長い計算には非同期を使用する必要があると記載されている必要があります。長い計算と見なされるものは何ですか?100ms?300ms?5秒?10秒?私の推測では1秒以上のことですが、それをどのように判断するのですか?

この質問の理由は、非同期コントローラー呼び出しのテストが通常の呼び出しよりもはるかに難しいためです。メソッドを呼び出してその戻り値をチェックするだけでなく、偽のアプリケーションを起動して本格的なリクエストを実行する必要があります。

そうではなかったとしても、すべてを包み込むことが道であるAsyncAkka.futureは思えません。

#playframework IRCチャンネルでこれを求めましたが、答えがなく、どうすればよいかわからないのは私だけではないようです。

繰り返しになりますが:

  1. すべてのリクエストが/actionsプールから1人のアクターを割り当てるのは正しいですか?
  2. どういうparallelism-factor意味ですか、なぜそれは1ですか?
  3. とどうfork-join-executor違うのthread-pool-executor
  4. 計算がラップされるまでにどのくらいの時間が必要Asyncですか?
  5. 偽のアプリケーションを起動せずに非同期コントローラーメソッドをテストすることはできませんか?

前もって感謝します。

編集: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 ;)
4

2 に答える 2

6
  1. メッセージがアクターに到着すると、そのメッセージを処理するのにかかる限り、そのアクターを保持します。要求を同期的に処理する場合(そのメッセージの処理中に応答全体を計算する場合)、このアクターは、応答が完了するまで他の要求を処理できません。代わりに、このリクエストを受信したときに別のアクターに作業を送信できる場合、リクエストを受信したアクターは、最初のリクエストが他のアクターによって処理されている間に、次のリクエストの作業を開始できます。

  2. アクターに使用されるスレッドの数は「numcpus*parallelism-factor」です(ただし、最小値と最大値は指定できます)。

  3. ダンノ

  4. 実際の計算が行われていない限り、データベース/ファイルシステムでioを実行するなど、他のシステムと通信しているものはすべて非同期にする傾向があります。確かに、スレッドをブロックする可能性のあるものは何でも。ただし、メッセージを渡す際のオーバーヘッドは非常に少ないので、すべての作業を他のアクターに送信するだけで問題はないと思います。

  5. コントローラのテスト方法については、機能テストに関するPlayのドキュメントを参照してください。

于 2012-09-25T13:15:40.827 に答える
1

テストのためにこれを行うことができるようです:

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
于 2012-09-26T09:49:53.480 に答える