2012-09-25 62 views
16

我最近轉移到了Play框架2.0,並且關於控制器實際上如何工作的一些問題。Play框架2.0控制器/ Async究竟如何工作?

play docs可以舉出:

由於的方式播放2.0作品,動作代碼必須儘可能快 可能的(即,非阻擋)。

但是在another part of the docs

  /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-executorthread-pool有什麼不同?

另外 - 文檔應該說,異步應該用於長時間的計算。 什麼資格作爲長期計算? 100ms的? 300ms的? 5秒? 10秒?我的猜測會超過一秒鐘,但如何確定?

此質疑的原因是測試異步控制器調用比常規調用困難。你必須啓動一個虛假的應用程序並做一個完整的請求,而不是隻調用一個方法並檢查它的返回值。

即使情況並非如此,我懷疑包裝AsyncAkka.future的一切都是如此。

我在#playframework IRC頻道中詢問過這個問題,但沒有答案,似乎我不是唯一不知道該怎麼做的人。

只是重申:

  1. 是不是每一個請求分配從/動作池的一個演員?
  2. parallelism-factor是什麼意思?爲什麼是1?
  3. fork-join-executorthread-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 ;) 

回答

6
  1. 當消息演員到達演員,它只要它需要處理該消息保存到該演員。如果您同步處理請求(在處理該消息期間計算整個響應),則該響應完成之前,此actor不能處理其他請求。如果您可以在收到此請求後將作品發送給其他演員,則收到請求的演員可以在其他演員正在處理第一個請求時開始處理下一個請求。

  2. 用於演員線程的數量是「數的CPU *並行因子」(可以但指定的最小值和最大值)

  3. 說不上

  4. 除非有真正的計算回事,我'傾向於使任何與其他系統交談的東西異步,就像用數據庫/文件系統做io一樣。當然,任何可能阻止線程的東西。然而,由於傳遞消息的開銷很小,我不認爲將所有的工作交給其他參與者會有問題。

  5. 查看Play Documentation on functional tests關於如何測試您的控制器。

+0

關於點1.什麼是發送任務了別的演員,而不是僅僅增加線程數的效益/動作喜歡150 (用於150個並發動作)? – arturaz

+0

這樣想想吧。你的桌上有數以千計的事情要做。哪個會更有效率?從堆中取出一個,在其上工作,直到完成,然後在下一個工作。或者拿走他們的第一百五十名,每人在150種不同的東西之間分配你的時間。第一種效率更高,因爲您不會浪費時間在「上下文切換」上。這裏同樣如此。 – stew

+0

但是,將任務發送給另一個參與者也會導致上下文切換。有什麼好處? –

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