2013-06-20 18 views
20

Używam aplikacji Play Framework 2.1.1 z zewnętrzną biblioteką Java, która generuje wynik java.util.concurrent.Future. Używam scala future w przeciwieństwie do Akka, co uważam za słuszne w przypadku Play 2.1. Jak mogę zawinąć java.util.concurrent.Future do pliku scala.concurrent.Future, zachowując jednocześnie kodowanie nieblokujące?Opakowanie scala.concurrent.Future dla java.util.concurrent.Future

def geConnection() : Connection = { 
    // blocking with get 
    connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS) 
} 

Powyższy kod zwraca połączenie, ale używa się tak, że staje się blokowanie

def getConnectionFuture() : Future[Connection] = { 
    future { 
    // how to remove blocking get and return a scala future? 
    connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS) 
    } 
} 

Idealnie chcę funkcję scala zwracającą połączenia jako przyszłego podobnego kodu powyżej, ale bez kodu blokowania przez get. Co jeszcze muszę dodać do funkcji, aby nie blokować.

Wszelkie wskaźniki byłyby świetne.

+0

Która wersja Scali używasz? Począwszy od 2.10.x, Scala przyjęła przyszłość Akki jako swoją. –

+0

Play 2.1.1 używa Scala 2.10.0 pod osłonami –

Odpowiedz

21
import java.util.concurrent.{Future => JFuture} 
import scala.concurrent.{Future => SFuture} 

Nie można zawinąć JFuture z SFuture bez blokowania, ponieważ nie jest zwrotna w SFuture (onComplete) i istnieje tylko blokuje get w JFuture.

Wszystko, co możesz zrobić, to utworzyć dodatkowy wątek i zablokować go za pomocą get, a następnie wypełnić Promise z wynikiem get.

val jfuture: JFuture[T] = ??? 
val promise = Promise[T]() 
new Thread(new Runnable { def run() { promise.complete(Try{ jfuture.get }) }}).start 
val future = promise.future 

Można sprawdzić isDone w nieskończonej pętli, ale nie sądzę, że jest lepszy niż blokowanie.

+2

Uzgodnione. Całkowity wstyd, że przyszłość Java nie obsługuje jakiegoś kompletnego odbiornika/obserwatora dla wywołania zwrotnego – cmbaxter

+0

@cmbaxter, jeśli używasz Guava, istnieje 'ListenableFuture' – fge

+0

Tak więc myślałem na zasadzie callback dla java peice, że kiedy zakończony, będzie miał swój wynik w przyszłości scala. Rozglądamy się za przykładami wywołań zwrotnych zaimplementowanych w Javie (http://technology.amis.nl/2009/02/19/asynchronous-processing-in-java-applications-leveraging-those-multi-cores/), ale nie było na pewno zagrać w Play 2.1. Optymistycznie miałem nadzieję na proste opakowanie, ale nie wygląda na to, że jest to wykonalne, a wywołanie zwrotne java w funkcji scala wygląda tak, jak powinno. –

2
Future { 
    blocking { 
    jfuture.get 
    } 
} 

To pozwala ExecutionContext wiedzieć, że to co robisz ma zamiar blokować, dając mu szansę przeznaczyć więcej wątków. Jeśli nie dodasz blocking { }, możesz zabraknąć wątków.

+0

Możesz chcieć podać szczegóły na temat tego, jakie są plusy i minusy tego. Czy to dokładnie to samo, co powyżej (w komentarzach np. Z @senia) – akauppi

+1

Przepraszam za to. Dodano komentarz wyjaśniający użycie "blokowania". –

+1

A jeśli zrobisz "blokowanie", możesz skończyć z dziesiątkami tysięcy wątków przy dużym obciążeniu. Bądź ostrożny - "blokowanie" nie jest magią! – folex

0

Biblioteka scala-java8-compat udostępnia konwertery między kontraktami java8 i Scala Futures.

Konkretnie, można użyć FutureConverters.toScala(connectionPool.getConnectionAsync()) do konwersji java.util.concurrent.Future do scala.concurrent.Future

+0

Ta odpowiedź wprowadza w błąd. scala-java8-compat umożliwia konwersję z 'java.util.concurrent.CompletionStage' na' scala.concurrent.Future'. Nie ma "właściwego" sposobu na konwersję Javy Future na Scala Future. – fcs

1
 import java.util.concurrent.{Future => JFuture} 
    import scala.concurrent.ExecutionContext.Implicits.global 
    import scala.concurrent.Future 
    import scala.util.Try 

    object JFuture2SFuture { 
     val jFuture: JFuture[Int] = ??? 
     val promise = Promise[Int]() 
     Future { promise.complete(Try(jFuture.get)) } //it is non blocking 
     val sFuture:Future[Int] = promise.future 

    } 
Powiązane problemy