2015-10-11 10 views
8

Vorrei implementare la mia elaborazione asincrona con scalaz.concurrent.Task. Ho bisogno di una funzione di (Task[A], Task[B]) => Task[(A, B)] per restituire un nuovo compito che funziona come segue:Come comporre due attività parallele per annullare un'attività se un'altra fallisce?

  • corsa Task[A] e Task[B] in parallelo e attendere i risultati;
  • se una delle attività non riesce, annulla il il secondo e attendi finché non termina;
  • restituisce i risultati di entrambe le attività.

Come implementare tale funzione?

+0

Ci sono diverse cose che _cancel_ potrebbe significare qui. Vuoi semplicemente che il calcolo fallisca velocemente? Allora qualcosa del tipo 'both' su' Nondeterminism' funzionerà. Se vuoi evitare anche sprecare cicli (o vuoi annullare gli effetti del calcolo ancora in esecuzione) sarà più complicato. –

+0

Sì, voglio solo che il calcolo fallisca velocemente per ora. – Michael

risposta

3

Come detto sopra, se non ti interessa arrestare effettivamente il calcolo non fallito, puoi utilizzare Nondeterminism. Per esempio:

import scalaz._, scalaz.Scalaz._, scalaz.concurrent._ 

def pairFailSlow[A, B](a: Task[A], b: Task[B]): Task[(A, B)] = a.tuple(b) 

def pairFailFast[A, B](a: Task[A], b: Task[B]): Task[(A, B)] = 
    Nondeterminism[Task].both(a, b) 

val divByZero: Task[Int] = Task(1/0) 
val waitALongTime: Task[String] = Task { 
    Thread.sleep(10000) 
    println("foo") 
    "foo" 
} 

E poi:

pairFailSlow(divByZero, waitALongTime).run // fails immediately 
pairFailSlow(waitALongTime, divByZero).run // hangs while sleeping 
pairFailFast(divByZero, waitALongTime).run // fails immediately 
pairFailFast(waitALongTime, divByZero).run // fails immediately 

In tutti i casi, tranne il primo l'effetto collaterale in waitALongTime accadrà. Se si desidera tentare di interrompere tale computazione, è necessario utilizzare qualcosa come Task's runAsyncInterruptibly.

2

C'è una strana idea tra gli sviluppatori java che non si dovrebbero cancellare attività parallele. Commiliano lo Thread.stop() e lo contrassegna deprecato. Senza Thread.stop() non potresti davvero cancellare il futuro. Tutto quello che puoi fare è inviare un segnale al futuro, o modificare alcune variabili condivise e rendere il codice in futuro per controllarlo periodicamente. Quindi, tutte le biblioteche che offrono future potrebbero suggerire l'unico modo per cancellare il futuro: farlo in modo cooperativo.

Sto affrontando lo stesso problema ora ed è nel mezzo di scrivere la mia libreria per i futures che potrebbero essere cancellati. Ci sono alcune difficoltà ma potrebbero essere risolte. Non puoi semplicemente chiamare Thread.stop() in nessuna posizione arbitraria. Il thread può eseguire l'aggiornamento delle variabili condivise. Il blocco verrebbe richiamato normalmente, ma l'aggiornamento potrebbe essere interrotto a metà, ad es. aggiornando solo la metà del doppio valore e così via. Quindi sto introducendo un blocco. Se il thread è in stato di protezione, dovrebbe ora essere ucciso da Thread.stop() ma con l'invio di un messaggio specifico. Lo stato protetto è considerato sempre molto veloce per essere aspettato. In qualsiasi altro momento, nel corso del calcolo, il thread potrebbe essere fermato in modo sicuro e sostituito con uno nuovo.

Quindi, la risposta è questa: non dovresti desiderare di cancellare il futuro, altrimenti sei un eretico e nessuno nella comunità java ti presterebbe una mano volenterosa. Dovresti definire il tuo contesto esecutivo che potrebbe uccidere i thread e dovresti scrivere la tua libreria dei futures per eseguire questo contesto

+0

Quale lingua/ambiente è accettabile con la cancellazione del thread non cooperativo? Una rapida ricerca mostra che né C# (http://stackoverflow.com/questions/14131608/how-to-terminate-a-thread-in-c), C++ 11 (http://stackoverflow.com/questions/ 12207684/how-do-i-terminate-a-thread-in-c11) o Python (http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in -python) non lo è. – thoredge

+0

normale c o C++.Ovviamente non è possibile farlo in modo portatile come puntatore, ma ogni SO ha le sue chiamate API thread che possono essere utilizzate dall'applicazione c o C++. Essere non portabile è normale per il codice c/C++ – ayvango