2015-06-24 4 views

Antwort

19

blocking wirkt als Hinweis auf die ExecutionContext, dass es Blockierungscode enthält, so dass es einen neuen Thread spawnen kann, um Deadlocks zu verhindern. Dies setzt voraus, dass die ExecutionContext das tun kann, aber nicht alle gemacht werden.

Schauen wir uns die einzelnen nacheinander an.


Future(blocking(blockingCall())) 

Dies erfordert eine implizite ExecutionContext die Future auszuführen. Wenn ExecutionContext verwendet wird, ist ein BlockContext (wie scala.concurrent.ExecutionContext.Implicits.global ist), kann es in der Lage sein, einen neuen Thread in seinem Thread-Pool zu spawnen, um den blockierenden Aufruf zu behandeln, wenn es erforderlich ist. Wenn nicht, passiert nichts Besonderes.


blocking(Future(blockingCall())) 

Dies sagt uns, dass Future(blockingCall()) eine Sperrstelle sein kann, so dass es die gleiche wie oben behandelt wird. Außer hier ist Future.apply nicht blockierend, also macht die Verwendung von blocking effektiv nichts anderes, als etwas Overhead hinzuzufügen. Es ist egal, was ExecutionContext wir nennen es von hier aus, da es sowieso nicht blockiert. jedoch, der blockierenden Aufruf innerhalb derFuture wird ein Gewinde in dem Block ExecutionContext es läuft auf, ohne den Hinweis, dass seine Blockierung. Also gibt es keinen Grund, dies jemals zu tun.

Ich habe blocking ausführlicher in this answer erklärt.


REPL Beispiele:

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

Es ist auch kein Schlüsselwort, es ist nur eine Methode. –

+0

Das war eine großartige Erklärung! Ich danke dir sehr! – Manu