viernes, 24 de febrero de 2017

Paralelización con RxJava

Para los que no lo sepan: Rx es monohilo por defecto. 

Un entorno multihilo rompe un stream secuencial inmutable; puesto que deja de ser secuencial.

Aun así, todavía hay posibilidad (y potencial) de ejecutar procesos en paralelo.


Empecemos por un sencillo ejemplo en el que nos subscribimos a una lista de enteros:


public static int DoHeavyThings(int i) {
        Thread.sleep(5000);
        return i;
}
Observable<Integer> nums = Observable.range(1,10);
nums.map(n -> DoHeavyThings(n))
          .subscribe(res -> System.out.println(res + " --> " + Thread.currentThread().getName()));

Esto se ejecuta en el hilo principal y bloqueamos la UI... Probemos a suscribirnos a otro/s hilo/s usando un scheduler para computación cuya implementación escala según los núcleos de nuestra computadora.

nums.subscribeOn(Schedulers.computation())
          .map(n -> DoHeavyThings(n))
          .subscribe(res -> System.out.println(res + " --> " + Thread.currentThread().getName()));

Pues tampoco... Usa otro hilo y no bloquea la UI pero sólo usa un hilo y sigue procesando lo elementos de forma secuencial.

¿Cómo puedo hacer esto sin escapar de la mónada?

La respuesta es crear un stream inmutable por cada elemento y suscribir cada uno al scheduler:

nums.flatMap(n -> Observable.just(n)
            .subscribeOn(Schedulers.computation())
            .map(o -> intenseCalculation(o))
)  .subscribe(res -> System.out.println(res + " --> " + Thread.currentThread().getName()));

Hemos fastidiado el orden de la secuencia pero tenemos cálculos en paralelo.

Yo a esto le veo potencial. Imaginaos que no disponemos de GPU y debemos procesar los pixeles de una imagen para algún efecto visual. Se podría dividir la imagen en secciones, dejar que cada hilo procese una sección y después volver a montar la imagen procesada con los items del stream final que pueden incluir, a parte de la sección de la imagen, metainformación suficiente para remontar la imagen.

Si el procesado de las secciones de la imagen requiere consultas a pixeles vecinos para los calculos siempre se puede precalcular las derivadas parciales de los pixeles que bordean la sección y pasarlas también como metainformación de esa secciónn de la imagen.

Y como todo está implementado con Rx podemos ir mostrando en la UI las secciones procesadas en cuanto vayan llegando, produciendo un efecto de peli de hackers bien molón e increiblemente fácil de implementar. :-D

Happy coding bastardillos!


No hay comentarios:

Publicar un comentario