2015-06-24 11 views

risposta

19

blocking funge da suggerimento per ExecutionContext che contiene codice di blocco, in modo che possa generare un nuovo thread per evitare deadlock. Ciò presuppone che lo ExecutionContext possa farlo, ma non tutti sono fatti per.

Diamo un'occhiata a ciascuno uno per uno.


Future(blocking(blockingCall())) 

Questo richiede un implicito ExecutionContext per eseguire il Future. Se lo ExecutionContext utilizzato è un BlockContext (come scala.concurrent.ExecutionContext.Implicits.global), potrebbe essere in grado di generare un nuovo thread nel suo pool di thread per gestire la chiamata di blocco, se necessario. Se non lo è, allora non succede nulla di speciale.


blocking(Future(blockingCall())) 

Questo ci dice che Future(blockingCall()) può essere una chiamata di blocco, quindi viene trattato lo stesso come sopra. Tranne che qui, Future.apply non è bloccante, quindi l'uso di blocking non fa altro che aggiungere un po 'di overhead. Non importa che cosa lo chiamiamo ExecutionContext da qui, in quanto non blocca comunque. Tuttavia , la chiamata di blocco all'interno il Future bloccherà un filo nella ExecutionContext cui sta girando, senza il suggerimento che il suo bloccaggio. Quindi, non c'è motivo di farlo mai.

Ho spiegato blocking in profondità in this answer.


Esempi REPL:

import java.util.concurrent.Executors 
import scala.concurrent._ 
val ec = scala.concurrent.ExecutionContext.Implicits.global 
val executorService = Executors.newFixedThreadPool(4) 
val ec2 = ExecutionContext.fromExecutorService(executorService) 

def blockingCall(i: Int): Unit = { Thread.sleep(1000); println("blocking call.. " + i) } 

// Spawns enough new threads in `ec` to handle the 100 blocking calls 
(0 to 100) foreach { i => Future(blocking(blockingCall(i)))(ec) } 

// Does not spawn new threads, and `ec2` reaches thread starvation 
// execution will be staggered as threads are freed 
(0 to 100) foreach { i => Future(blocking(blockingCall(i)))(ec2) } 

// `blocking` does nothing because the `Future` is executed in a different context, 
// and `ec2` reaches thread starvation 
(0 to 100) foreach { i => blocking(Future(blockingCall(i))(ec2)) } 

// `blocking` still does nothing, but `ec` does not know to spawn new threads (even though it could) 
// so we reach thread starvation again 
(0 to 100) foreach { i => blocking(Future(blockingCall(i))(ec)) } 
+2

Non è anche una parola chiave, è solo un metodo. –

+0

Questa è stata una grande spiegazione! Grazie mille! – Manu