2014-06-11 11 views
11

Poiché Netty è un server non bloccante, quale effetto cambia una azione nell'uso di .async?Che effetto ha utilizzando Action.async, dal momento che Play utilizza Netty che non è bloccante

def index = Action { ... } 

contro

def index = Action.async { ... } 

Capisco che con .async si otterrà un Future[SimpleResult]. Ma dal momento che Netty non blocca, giocherà comunque qualcosa di simile sotto le coperte?

Che effetto avrà sul throughput/scalabilità? È una domanda difficile a cui rispondere dove dipende da altri fattori?

Il motivo che chiedo è, ho il mio personalizzato Action e volevo resettare il timeout dei cookie per ogni richiesta di pagina in modo che sto facendo questo, che è una chiamata async:

object MyAction extends ActionBuilder[abc123] { 
    def invokeBlock[A](request: Request[A], block: (abc123[A]) => Future[SimpleResult]) = { 
    ... 
    val result: Future[SimpleResult] = block(new abc123(..., result)) 
    result.map(_.withCookies(...)) 
    } 
} 

Il togliere dal frammento di cui sopra è sto usando un Future[SimpleResult], è simile a chiamare Action.async ma questo è all'interno della mia azione stessa?

Voglio capire che effetto avrà sul mio design dell'applicazione. Sembra che solo per la possibilità di impostare il mio cookie su base per richiesta sono passato dal blocco al non-blocco. Ma sono confuso da quando Netty non sta bloccando, forse non ho davvero cambiato nulla nella realtà dato che era già asincrono?

Oppure ho semplicemente creato un'altra chiamata asincrona incorporata in un'altra?

Sperando che qualcuno possa chiarire questo con alcuni dettagli e come o quale effetto ciò avrà nel rendimento/velocità effettiva.

risposta

18

def index = Action { ... } non è bloccante hai ragione.

Lo scopo di Action.async è semplicemente quello di semplificare il lavoro con Futures nelle azioni.

Ad esempio:

def index = Action.async { 
    val allOptionsFuture: Future[List[UserOption]] = optionService.findAll() 
    allOptionFuture map { 
    options => 
     Ok(views.html.main(options)) 
    } 
} 

Ecco il mio servizio restituisce un Future, e per evitare di trattare con l'estrazione del risultato ho appena farlo corrispondere ad un Future[SimpleResult] e Action.async si prende cura di tutto il resto.

Se il mio servizio stava restituendo List[UserOption] direttamente potrei semplicemente usare Action.apply, ma sotto il cofano sarebbe ancora non bloccante.

Se si guarda alla Action codice sorgente, si può anche vedere che alla fine chiama applyasync: https://github.com/playframework/playframework/blob/2.3.x/framework/src/play/src/main/scala/play/api/mvc/Action.scala#L432

+0

Vedo, così nel mio "MyAction" qual è l'effetto netto dell'utilizzo di me utilizzando un futuro e callinf result.map? E se faccio Myaction.async nel mio controller? (rispetto all'utilizzo dell'azione predefinita) – Blankman

+1

Bene, ho pensato di aver risposto alla tua domanda. Dovresti dare un'occhiata a questa pagina della documentazione: http://www.playframework.com/documentation/2.3.x/ScalaAsync – vptheron

+1

Grazie ho letto prima. Quindi avere un futuro che chiama un futuro ecc. In realtà non influisce sulle prestazioni per dire? – Blankman

0

mi è capitato di imbattersi in questa domanda, mi piace la risposta da @vptheron, e ho anche voler condividere qualcosa che ho letto dal libro "Applicazioni Web reattive", che, penso, è anche grande.

Il Action.async builder aspetta di avere una funzione di tipo Request => Future[Result]. Le azioni dichiarate in questo modo non sono molto diverse dalle semplici chiamate Action { request => ... }, l'unica differenza è che Play sa che le azioni Action.async sono già asincrone, quindi non avvolgono il loro contenuto in un blocco futuro.

Proprio così - Play programmerà per impostazione predefinita qualsiasi corpo azione da eseguire in modo asincrono rispetto al pool di worker Web predefinito, eseguendo il wrapping in un futuro. L'unica differenza tra Action e Action.async è che nel secondo caso, ci stiamo occupando di fornire un calcolo asincrono.

Inoltre presentato un campione:

def listFiles = Action { implicit request => 
    val files = new java.io.File(".").listFiles 
    Ok(files.map(_.getName).mkString(", ")) 
} 

che è problematico, dato il suo uso del blocco java.io.File API.

Qui l'API java.io.File sta eseguendo un'operazione di I/O di blocco, il che significa che uno dei pochi fili della piscina lavoratore web di gioco sarà dirottato mentre il sistema operativo capisce l'elenco dei file nella directory di esecuzione. Questo è il tipo di situazione che dovresti evitare a tutti i costi, perché significa che il pool di lavoro potrebbe esaurire i thread.

-

Lo strumento di controllo reattivo, disponibile presso https://github.com/octo-online/reactive-audit, mira a sottolineare le chiamate di blocco in un progetto.

Spero che sia d'aiuto.

Problemi correlati