2012-09-25 13 views
16

Niedawno przeniosłem się do Play 2.0 i mam kilka pytań dotyczących tego, jak kontrolery rzeczywiście działają w grze.Jak dokładnie działają konsole Play 2.0/Async?

W play docs można wymienić:

Ze względu na sposób Zagraj 2.0 dzieła, kod działanie musi być tak szybko, jak to możliwe (czyli bez blokowania.).

Jednak w another part of the docs:

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

i

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

Wydaje się, że istnieje 24 aktorów dedykowanych kontrolerów obsługujących. Domyślam się, że każde żądanie przydziela jednego z tych aktorów na cały okres trwania wniosku. Czy to prawda?

Co ponadto oznacza parallelism-factor i jak różni się fork-join-executor od thread-pool?

Również - docs powinni powiedzieć, że Async powinien być używany do długich obliczeń. Co kwalifikuje się jako długie obliczenie? 100ms? 300ms? 5 sekund? 10 sekund? Zgaduję, że to coś ponad sekundę, ale jak to ustalić?

Powodem tego pytania jest to, że testowanie połączeń kontrolera asynchronicznego jest o wiele trudniejsze niż zwykłe połączenia. Musisz uruchomić fałszywą aplikację i wykonać pełne żądanie, zamiast tylko wywoływać metodę i sprawdzać jej wartość zwracaną.

Nawet jeśli tak nie było, to wątpię, że zawijanie wszystkiego w Async i Akka.future jest drogą.

Poprosiłem o to w kanale IRC#playframework, ale nie było odpowiedzi i wydaje się, że nie jestem jedyną osobą, która nie jest pewna, jak należy postąpić.

Wystarczy powtórzyć:

  1. Czy to prawda, że ​​każdy wniosek przydziela jednego aktora z/działań basenie?
  2. Co oznacza parallelism-factor i dlaczego jest to 1?
  3. Czym różni się fork-join-executor od thread-pool-executor?
  4. Jak długo należy obliczać owijanie w Async?
  5. Czy nie można przetestować metody kontrolera asynchronicznego bez tworzenia fałszywych aplikacji?

Z góry dziękuję.

Edycja: niektóre rzeczy z IRC

jakiś materiał z 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 ;) 

Odpowiedz

6
  1. Po otrzymaniu wiadomości na aktora aktorem, to trzyma się tego aktora, tak długo jak trzeba, aby przetworzyć tę wiadomość. Jeśli przetwarzasz żądanie synchronicznie (oblicz całą odpowiedź podczas przetwarzania tego komunikatu), wówczas ten aktor nie może obsługiwać innych żądań, dopóki odpowiedź nie zostanie wykonana. Jeśli zamiast tego możesz, po otrzymaniu tego wniosku, wysłać pracę innemu podmiotowi, aktor, który otrzymał wniosek, może rozpocząć pracę nad kolejnym żądaniem, podczas gdy pierwszy wniosek jest przetwarzany przez inne podmioty.

  2. Liczba wątków używanych do aktorów jest "num procesory * równoległość-factor" (można jednak określić min i max)

  3. wiem

  4. ile istnieją realne wyliczenia dzieje, ja Zwykle asynchronizuje wszystko, co mówi do innego systemu, na przykład robi to z bazą danych/systemem plików. Z pewnością wszystko, co mogłoby zablokować wątek. Ponieważ jednak przekazywanie wiadomości jest tak niewielkie, nie sądzę, aby istniał problem z wysyłaniem całej pracy innym aktorami.

  5. Zobacz, jak przetestować kontrolery na stronie Play Documentation on functional tests.

+0

O punkcie 1. Jakie korzyści wysyłania zadań off do innych podmiotów, a nie tylko zwiększenie liczby wątków na/działań lubić 150 (dla 150 równoczesnych działań)? – arturaz

+0

Pomyśl o tym w ten sposób. Masz na biurku setkę rzeczy do zrobienia. Który byłby bardziej wydajny? zdejmij jeden ze stosu, pracuj nad nim do końca, a następnie przejdź do następnego. Lub weź 150 pierwszych i pracuj na każdym z nich, dzieląc czas pomiędzy 150 różnych rzeczy. Pierwszy jest bardziej wydajny, ponieważ nie tracisz czasu na "przełączniki kontekstu". To samo dotyczy tutaj. – stew

+0

Ale wysłanie zadania do innego aktora prowadzi również do przełączenia kontekstu. Jakie są korzyści? –

1

Wydaje się, że można to zrobić do testowania:

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