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)) }
Es ist auch kein Schlüsselwort, es ist nur eine Methode. –
Das war eine großartige Erklärung! Ich danke dir sehr! – Manu