2012-09-25 10 views
16

Ich bin kürzlich zu Play Framework 2.0 gewechselt und es gibt einige Fragen, die mich betreffen, wie Controller tatsächlich im Spiel funktionieren.Wie funktioniert Play Framework 2.0 Controller/Async?

In play docs sind zu erwähnen:

Aufgrund der Art und Weise spielen 2.0 funktioniert, muss der Aktionscode sein, so schnell wie möglich (dh nicht Blockierung.).

jedoch in another part of the docs:

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

und

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

Es scheint, dass es 24 Akteure für Controller zugewiesen Handhabung. Ich denke, jede Anfrage weist einen dieser Akteure für die gesamte Lebensdauer der Anfrage zu. Ist das richtig?

Auch was bedeutet parallelism-factor und wie unterscheidet sich fork-join-executor von thread-pool?

Auch - Dokumente sollten sagen, dass Async für lange Berechnungen verwendet werden sollte. Was ist eine lange Berechnung? 100ms? 300ms? 5 Sekunden? 10 Sekunden? Meine Vermutung wäre etwas über eine Sekunde, aber wie kann man das feststellen?

Der Grund für diese Frage ist, dass das Testen asynchroner Controller-Aufrufe viel schwieriger ist als normale Anrufe. Sie müssen eine gefälschte Anwendung hochfahren und eine vollständige Anfrage ausführen, anstatt nur eine Methode aufzurufen und ihren Rückgabewert zu überprüfen.

Auch wenn das nicht der Fall war, bezweifle ich, dass alles in Async und Akka.future Verpackung ist der Weg.

Ich habe dies in #playframework IRC-Kanal gefragt, aber es gab keine Antwort und es scheint, dass ich nicht der einzige bin nicht sicher, wie die Dinge getan werden sollten.

nur zu wiederholen:

  1. Ist es richtig, dass jede Anfrage ein Akteur aus/Aktionen Pool zuordnet?
  2. Was bedeutet parallelism-factor und warum ist es 1?
  3. Wie unterscheidet sich fork-join-executor von thread-pool-executor? Wie lange sollte eine Berechnung in Async verpackt werden?
  4. Ist es nicht möglich, asynchrone Controller-Methoden zu testen, ohne gefälschte Anwendungen zu starten?

Vielen Dank im Voraus.

Edit: ein paar Sachen von IRC

ein paar Sachen von 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 ;) 

Antwort

6
  1. Wenn eine Nachricht auf einem Schauspieler einen Schauspieler ankommt, halten sie an diesen Schauspieler auf, solange sie diese Nachricht zu verarbeiten braucht. Wenn Sie die Anforderung synchron verarbeiten (die gesamte Antwort während der Verarbeitung dieser Nachricht berechnen), kann dieser Akteur keine anderen Anforderungen bedienen, bis die Antwort erfolgt ist. Wenn stattdessen können Sie, nach dem Empfang dieser Anforderung senden Arbeit an einen anderen Akteur aus, der Schauspieler, der die Anforderung empfangen wird, kann die Arbeit am nächsten Anfrage starten, während die erste Anforderung von anderen Akteuren an denen gearbeitet wird.

  2. Die Anzahl der Threads für Schauspieler ist "num Cpus * Parallelität-Faktor" verwendet

  3. Dunno

  4. Es sei denn, es gibt reale Berechnungen gehen, ich (Sie jedoch min und max angeben) würde dazu neigen, alles, was mit einem anderen System kommuniziert, asynchron zu machen, wie io mit einer Datenbank/einem Dateisystem zu tun. Sicherlich alles, was den Thread blockieren könnte. Da es jedoch so wenig Aufwand beim Weiterleiten von Nachrichten gibt, glaube ich nicht, dass es ein Problem damit geben würde, die gesamte Arbeit an andere Akteure zu senden.

  5. Siehe Play Documentation on functional tests darüber, wie Ihre Controller zu testen.

+0

über Punkt 1. Was ist der Nutzen von Aufgaben aus in andere Akteure statt nur zunehmende Anzahl von Threads für das Senden/Aktionen 150 zu mögen (für 150 gleichzeitige Aktionen)? – arturaz

+0

Denken Sie darüber nach. Sie haben einen Haufen hunderter Dinge auf Ihrem Schreibtisch. Was wäre effizienter? Ziehe einen vom Stapel, arbeite daran, bis es fertig ist, und arbeite dann am nächsten. Oder nehmen Sie die ersten 150 von ihnen und arbeiten Sie ein kleines bisschen auf jeder Ihrer Zeit zwischen 150 verschiedenen Dingen aufteilen. Der erste ist effizienter, weil Sie keine Zeit mit "Kontextwechsel" verschwenden. Das Gleiche gilt auch hier. – stew

+0

Das Senden der Aufgabe an einen anderen Akteur führt jedoch auch zu einem Kontextwechsel. Was ist der Vorteil? –

1

Es scheint, dass Sie dies für die Prüfung tun:

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 
Verwandte Themen