6

Ho scritto una funzione che genera un labirinto basato sulla casualità. La maggior parte delle volte questa funzione è molto veloce. Ma ogni tanto, a causa della sfortuna con i numeri casuali, ci vogliono un paio di secondi.Esegui calcoli concorrenti in parallelo e scarta tutti tranne il primo che termina

Vorrei avviare questa funzione più volte in parallelo e lasciare che la funzione più veloce "vinca".

La libreria standard di Scala (o la libreria standard Java) fornisce uno strumento di adattamento per questo lavoro?

+3

potrebbe essere più facile (e più efficiente) per scoprire perché il programma prende a volte un paio di secondi e risolvere il problema ... – immibis

+0

si consiglia [ExecutorCompletionService] (http://docs.oracle .com/javase/7/docs/api/java/util/concurrent/ExecutorCompletionService.html), ma sono d'accordo con @immibis – hsluo

+0

@immibis Sembra che la generazione di labirinti (senza punti morti) sia solo un problema difficile, e ogni soluzione Ho trovato/posso pensare che richiede un pesante backtracking. – fredoverflow

risposta

1

Java 8 soluzione CompletableFuture:

public class FirstDoneWithCompletableFutureEx { 

    public static void main(String[] args) throws ExecutionException, InterruptedException { 

     int jobs = 10; 
     CompletableFuture<?>[] futures = new CompletableFuture[jobs]; 
     for (int i = 0; i < jobs; i++) { 
      futures[i] = CompletableFuture.supplyAsync(() -> { 
       //computation  
       return new Object(); 
      }); 
     } 

     //first job done 
     Object firstDone = CompletableFuture.anyOf(futures).get(); 
    } 
} 

Una soluzione java 5,6,7 con.210:

public class FirstDoneWithCompletionServiceEx { 

    public static void main(String[] args) throws InterruptedException, ExecutionException { 

     int jobs = 10; 
     ExecutorService executorService = Executors.newFixedThreadPool(jobs); 
     CompletionService<Object> completionService = new ExecutorCompletionService<>(executorService); 

     for (int i = 0; i < jobs; i++) 
      completionService.submit(
        new Callable<Object>() { 
         @Override 
         public Object call() throws Exception { 
          //computation 
          return new Object(); 
         } 
        } 
      ); 

     //get first job done 
     Object firstDone = completionService.take().get(); 

     executorService.shutdownNow(); 
    } 
} 
+0

Questa sembra un'occasione perfetta per usare CompletableFuture con un acceptEither CompletionStage. – TechTrip

5

È possibile utilizzare Future:

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

val futures = for (_ <- 1 to 4) yield Future { /* computation */ } 
val resultFuture = Future.firstCompletedOf(futures) 

Se si desidera bloccare (presumo si fa), è possibile utilizzare Await.result:

import scala.concurrent.Await 
import scala.concurrent.duration.Duration 

val result = Await.result(resultFuture, Duration.Inf) 
+0

Esiste un modo semplice per annullare i calcoli in sospeso al termine del primo calcolo? – fredoverflow

+0

@FredOverflow vedi questa domanda: http://stackoverflow.com/questions/16009837/how-to-cancel-future-in-scala – rightfold