Wie konfiguriere ich einen fein abgestimmten Thread-Pool für Futures?

80

Wie groß ist Scalas Thread-Pool für Futures?

Meine Scala-Anwendung macht viele Millionen future {}s und ich frage mich, ob ich irgendetwas tun kann, um sie durch Konfigurieren eines Thread-Pools zu optimieren.

Vielen Dank.

Erik Kaplun
quelle
Slick 3.0 verwendet eine eigene Verbindung und einen eigenen Threadpool. Warum müssen wir also einen impliziten Ausführungskontext für Slick bereitstellen, wenn der eigene
Threadpool
1
@ RahulGulabani, aus dem Buch "Essential Slick":The reason is that map, flatMap methods of Action allows you to call arbitrary code when joining the actions together. Slick cannot allow that code to be run on its own execution context, because it has no way to know if you are going to tie up Slicks threads for a long time.
Srzhio

Antworten:

90

Sie können Ihren eigenen ExecutionContext angeben, in dem Ihre Futures ausgeführt werden, anstatt den globalen impliziten ExecutionContext zu importieren.

import java.util.concurrent.Executors
import scala.concurrent._

implicit val ec = new ExecutionContext {
    val threadPool = Executors.newFixedThreadPool(1000)

    def execute(runnable: Runnable) {
        threadPool.submit(runnable)
    }

    def reportFailure(t: Throwable) {}
}
Josh Gao
quelle
72
Gute Antwort, Sie können das Boilerplate ein wenig reduzieren, indem Sie die Hilfsmethoden in ExecutionContext verwenden, mit denen Sie direkt von einem bestimmten Executor aus instanziieren können. ZB impliziter Wert ec = ExecutionContext.fromExecutor (Executors.newFixedThreadPool (10))
sksamuel
1
Zugegeben, das ist alles schön, aber gibt es eine echte Grenze in Threads auf implicits.global? Wenn ja, ist dies wie akka über application.conf konfigurierbar?
Nick
6
@Nick ja, implicits.global ist nur 1 Thread pro CPU-Kern. Optimal für CPU-gebundene Aufgaben. Für klassische blockierende E / A (z. B. jdbc) ist dies jedoch eine Leistungskatastrophe.
Ben Hutchison
2
Ich musste einen Aufruf hinzufügen, um den Thread-Pool nach dieser Verwendung herunterzufahren, oder das Programm wird nie beendet ... def shutdown () = threadPool.shutdown ()
justinhj
2
Warum wird es im "normalen" Fall heruntergefahren, aber nicht, wenn wir das Implizite auf etwas anderes setzen?
Hbogert
152

Diese Antwort stammt von Monkjack, einem Kommentar aus der akzeptierten Antwort. Man kann diese großartige Antwort jedoch übersehen, also poste ich sie hier neu.

implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))

Wenn Sie nur die Anzahl der Thread-Pools ändern müssen, verwenden Sie einfach den globalen Executor und übergeben Sie die folgenden Systemeigenschaften.

-Dscala.concurrent.context.numThreads=8 -Dscala.concurrent.context.maxThreads=8
Bienvenido David
quelle
2
Dies ist eine elegantere Lösung
Ben Hutchison
Ich habe beide mit dem Wert 5 ausprobiert und sehe immer noch bis zu 8 Threads gleichzeitig.
Micseydel
3

Der beste Weg, um Threadpool in Scala-Futures anzugeben:

implicit val ec = new ExecutionContext {
      val threadPool = Executors.newFixedThreadPool(conf.getInt("5"));
      override def reportFailure(cause: Throwable): Unit = {};
      override def execute(runnable: Runnable): Unit = threadPool.submit(runnable);
      def shutdown() = threadPool.shutdown();
    }
Neeraj Bansal
quelle
0
class ThreadPoolExecutionContext(val executionContext: ExecutionContext)

object ThreadPoolExecutionContext {

  val executionContextProvider: ThreadPoolExecutionContext = {
    try {
      val executionContextExecutor: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(25))
      new ThreadPoolExecutionContext(executionContextExecutor)
    } catch {
      case exception: Exception => {
        Log.error("Failed to create thread pool", exception)
        throw exception
      }
    }
  }
}
VAIBHAV GOUR
quelle