Este documento presenta los conceptos básicos de la programación asíncrona. Explica que existen diferentes implementaciones como callbacks, observables y futuros para manejar código asíncrono. Detalla las ventajas de usar programación asíncrona como aprovechar mejor los recursos del sistema, pero también las desventajas como una mayor complejidad y propensión a errores. Finalmente, describe diversas formas de crear, completar y combinar futuros para interactuar de manera asíncrona entre llamadas.
10. Asynchronous programming is different
No podemos asumir que dentro de N líneas
de código dispondremos del resultado de
una llamada asíncrona
A B C
Cuando termine B
async
Programación declarativa
11. ¿Qué nos da? Potencia
Distintos cores para tareas costosas
Sistema de hilos para esperas largas
12. Más propenso a fallos
Hilos colgados
Sobrecarga de memoria
Difícil de depurar
¿Qué conlleva? Complejidad
18. Hay distintas implementaciones
Callbacks Futures
ExecutorService executor = Executors.newFixedThreadPool(3);
final GetCourseInfo getCourseInfo = new GetCourseInfo();
List<Future<Course>> futures = new ArrayList<>();
for (int i=1; i<=3; i++){
final int id = i;
Future<Course> future = executor.submit(
() -> getCourseInfo.apply(id).get()
);
futures.add(future);
}
for (Future<Course> future : futures){
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {}
}
Observers
19. Hay distintas implementaciones
val p = Promise[Optional[Course]]()
val f = p.future
val producer = Future {
val r = new GetCourseInfo() apply (1)
p success r
}
Future {
f onComplete {
case Success(optional) =>
println(JsonSerializer.PRETTY.serialize(optional.get()))
}
}
Callbacks Futures PromisesObservers
23. ¿Qué podemos hacer con los futuros?
Crearlos
CompletableFuture<Void> voidFuture = CompletableFuture.runAsync(
() -> System.out.println("Soy asíncrono!!"));
CompletableFuture<String> futureValue = CompletableFuture.supplyAsync(
() -> "En el futuro devolveré esta cadena");
CompletableFuture<String> fakeFuture =
CompletableFuture.completedFuture("Esto es útil en Tests");
24. ¿Qué podemos hacer con los futuros?
Obtener su valor de manera síncrona
try {
String value = futureValue.get(5L, TimeUnit.SECONDS);
} catch (InterruptedException|ExecutionException|TimeoutException e){ }
String value2 = futureValue2.join();
String value3 = futureValue3.getNow("");
¡OJO!
25. ¿Qué podemos hacer con los futuros?
Tratar su resultado de manera asíncrona
future.thenApply( String::toUpperCase );
future.thenAccept( System.out::println );
future.thenRun( () -> System.out.println("La tarea terminó") );
future.handle((v, ex) -> {
if (ex != null) return null;
else return v;
} );
future.whenComplete((v, ex) -> {
if (v != null) System.out.println(v);
} );
26. ¿Qué podemos hacer con los futuros?
Interactuar con otro futuro
// Una llamada depende de la otra
CompletableFuture<Integer> future = duplicateAsync(3)
.thenCompose( n -> duplicateAsync(n));
//Combinar dos llamadas en paralelo
future1 = CompletableFuture.supplyAsync( () -> "MOLA");
future2 = CompletableFuture.supplyAsync( () -> "MAZO");
CompletableFuture<String> combine = future1.thenCombine(future2,
(s1, s2) -> s1 + " " + s2);
27. ¿Qué podemos hacer con los futuros?
Interactuar con muchos futuros
// Se queda con el primer futuro que se resuelva
CompletableFuture<Object> fastest = CompletableFuture.anyOf(futuresArray);
fastestFuture.whenComplete((course, th) -> {
if(th == null) {
System.out.println( course);
}
});
// Espera hasta resolver todos los futuros
CompletableFuture<Void> all = CompletableFuture.allOf(arrayOfFutures);
all.thenAccept(v -> {
Arrays.stream(arrayOfFutures)
.map(CompletableFuture::join)
.forEach(System.out::println);
});
28. ¿Qué podemos hacer con los futuros?
Completarlos (promesas)
public class SingleEventNotifier{
final CompletableFuture<EventInfo> futureEvent;
public SingleEventNotifier(EventEmitter emitter) {
this.futureEvent = new CompletableFuture<>();
emitter.subscribe(this);
}
public CompletableFuture<EventInfo> ask(){
return futureEvent;
}
public void onEventReceived(EventInfo event){
futureEvent.complete(event);
}
}