2017-06-27 4 views
2

Ich bin mir bewusst, dass in Java 8 es keine gute Idee ist, zu starten lang laufenden Aufgaben im Strom Rahmen des Filters, Karte etc. Methoden, da es keine ist Art und Weise die zugrunde liegende Gabel-join Pool abzustimmen und es kann Latenzprobleme und starvings verursachen.Scala: Futures mit Karte, flatMap für IO/CPU gebunden Aufgaben

Nun meine Frage wäre, ist es ein Problem wie das mit Scala? Ich habe versucht, es zu googeln, aber ich denke, ich kann einfach nicht diese Frage stelle in einem Google-able Satz.

Lassen Sie uns sagen, ich habe eine Liste von Objekten, und ich möchte, dass sie in eine Datenbank speichern eine forEach verwenden, würde das keine Probleme verursachen? Ich denke, das würde nicht in Scala ein Problem sein, als funktionelle Transformationen grundlegende Bausteine ​​der Sprache sind, aber trotzdem ...

Antwort

1
  • Wenn Sie nicht jede Art von I/O-Operationen sehen dann Futures kann ein Overhead sein.

    def add(x: Int, y: Int) = Future { x + y }

  • Ausführen rein CPU-gebundenen Operationen in einem zukünftigen Konstruktor wird Ihre Logik langsamer auszuführen, nicht schneller. Mapping und Flatmapping über sie können den Treibstoff für dieses Problem erhöhen.

  • Wenn Sie eine Future mit einer konstanten/einfachen Berechnung initialisieren möchten, können Sie Future.successful() verwenden.

  • Aber alle Blocking I/O, SQL-Abfragen einschließlich macht Sinn innerhalb einer Future mit blocking

    Eg gewickelt werden:

    wie

    import scala.concurrent.blocking Future { blocking { DB.withConnection { implicit connection => val query = SQL("select * from bar") query() } }

  • Future { DB.withConnection { implicit connection => val query = SQL("select * from bar") query() } } getan werden sollte

    diese blocking benachrichtigt den Thread-Pool, dass diese Aufgabe Block ist König. Dies ermöglicht es dem Pool, nach Bedarf neue Arbeiter zu spawnen. Dies wird gemacht, um das Verhungern bei blockierenden Anwendungen zu verhindern.

  • Der Thread-Pool (standardmäßig die scala.concurrent.ExecutionContext.global Pool) weiß, wann der Code in einer blocking abgeschlossen ist. (Da es sich um eine Gabel verbinden Thread-Pool ist)

  • Deshalb wird es die Ersatzarbeitsthreads zu entfernen, da sie abgeschlossen und der Pool wird mit der Zeit wieder auf die erwartete Größe verkleinert (Anzahl der Kerne standardmäßig).

  • Dieses Szenario kann jedoch auch fehlschlagen, wenn nicht genügend Speicher zum Erweitern des Thread-Pools vorhanden ist.

  • Also für Ihr Szenario können Sie

    images.foreach(i => { 
    
        import scala.concurrent.blocking 
        Future { 
        blocking { 
         DB.withConnection { implicit connection => 
         val query = SQL("insert into .........") 
         query() 
        } 
        } 
    }) 
    
  • verwenden Wenn Sie eine Menge von Blockierung ich tun/O, dann ist es eine gute Praxis, einen separaten Thread-Pool/Ausführungskontext zu erstellen und Führe alle blockierenden Aufrufe in diesem Pool aus.

Referenzen:

Hoffnung, das hilft.

+0

Bitte beachten Sie, dass 'blocking' nur eine Empfehlung ist: https://stackoverflow.com/questions/29068064/scala-concurrent-blocking-what-does-it-actually-do und https://stackoverflow.com/ Fragen/19681389/Use-Case-of-Scala-gleichzeitige Blockierung – Yaneeve