Quali sono i vantaggi degli osservabili rispetto a un iterabile di futures?

2

Recentemente ho trovato il pattern ReactiveX per flussi di dati asincroni. Ho studiato le informazioni fornite e ho anche guardato questo talk da un tecnico Netflix su come hanno usato Observables per ridisegnare il loro web Architettura API.

ReactiveX sembra certamente un'astrazione pulita e potente, ma non vedo la differenza tra Observable<T> e Iterable<Future<T>> . Nel primo caso, potrei fare qualcosa come segue:

Observable<T> observable = getData()
observable.subscribe(onSuccess, onError, onCompletion)

E nel secondo caso, lo farei

Iterable<Future<T>> futures = getData()
futures.forEach(future => future.onSuccess(onSuccess), future.onError(onError))

dove onSuccess , onError e onCompletion sono alcune funzioni che ho definito altrove.

Quali vantaggi ha il primo esempio rispetto al secondo?

P.S. Questo è solo per curiosità. Attualmente utilizzo Python (e JavaScript) nel mio lavoro, quindi non userò il paradigma ReactiveX in qualsiasi momento.

    
posta gardenhead 07.05.2016 - 17:18
fonte

1 risposta

3

I tuoi esempi non sono equivalenti semanticamente:

Observable<T> observable = getData()
observable.subscribe(onSuccess, onError, onCompletion)

eseguirà le procedure onSuccess, onError ogni volta che viene ricevuto un nuovo elemento.

D'altra parte, con

Iterable<Future<T>> futures = getData()
futures.forEach(future => future.onSuccess(onSuccess), future.onError(onError))

l'iterable consegna tutti i futures e tu registrati i callback su ogni futuro mentre lo ottieni dal iterable. Ma, a questo punto, il futuro potrebbe ancora essere in esecuzione. Successivamente, questi futures possono essere completati in qualsiasi ordine, non necessariamente nell'ordine in cui sono stati forniti dall'iter iterabile.

Inoltre, la prima soluzione può ricevere un flusso di dati possibilmente illimitato senza bloccare: ogni volta che arriva un nuovo elemento, viene richiamata una richiamata. La seconda soluzione non può: ha senso solo se vuoi iniziare un finito numero di calcoli asincroni.

Per avere una migliore intuizione, dai un'occhiata alla tabella su questa pagina o questo (grazie a @Laiv per il link, non sono stato in grado di ritrovarlo).

  • Nella tua prima soluzione hai più valori spinti in modo asincrono nel tuo programma (in basso a destra della tabella).

  • Nella tua seconda soluzione hai più valori tirati in modo sincrono dal tuo programma. A turno, ognuno di questi valori è un calcolo che spinge asincronamente un singolo valore.

Un esempio di ciò che puoi fare con la prima soluzione è il seguente. Supponiamo di avere un osservabile che rappresenta tutti gli eventi della GUI in un'applicazione:

Observable<Event> events = ...

Ora se vuoi ascoltare solo gli eventi di un determinato pulsante che è, diciamo, identificato dalla sua etichetta "HelpButton", puoi scrivere l'osservabile:

Observable<Event> helpButtonEvents =
    events.filter(e => "HelpButton".equals(e.getName()))

helpButtonEvents.subscribe(onHelpInvoked, ..., ...)

Dovrebbe essere chiaro che non puoi usare un iterable di futuro qui, perché non sai quanti eventi della GUI avrai e quindi avresti bisogno di avere un iteratore che esegue il polling sugli eventi per sempre.

    
risposta data 07.05.2016 - 18:55
fonte

Leggi altre domande sui tag