O futuro chegou: Programao concorrente com futures LEONARDO BORGES - - PowerPoint PPT Presentation

o futuro chegou
SMART_READER_LITE
LIVE PREVIEW

O futuro chegou: Programao concorrente com futures LEONARDO BORGES - - PowerPoint PPT Presentation

O futuro chegou: Programao concorrente com futures LEONARDO BORGES SENIOR CLOJURE ENGINEER @LEONARDO_BORGES SOBRE Um pouco sobre mim Senior Clojure Engineer na Atlassian, Sydney Fundador do Grupo de Usurios Clojure


slide-1
SLIDE 1

LEONARDO BORGES • SENIOR CLOJURE ENGINEER • @LEONARDO_BORGES

O futuro chegou:

Programação concorrente com futures

slide-2
SLIDE 2

SOBRE

Um pouco sobre mim

  • Senior Clojure Engineer na

Atlassian, Sydney

  • Fundador do Grupo de Usuários

Clojure de Sydney

  • Autor de Clojure Reactive

Programming - http://bit.ly/cljRp

* QCon discount code: CRP10

slide-3
SLIDE 3

CONCORRÊNCIA FUTURES

O quê?

ABSTRAÇÃO COMPOSIÇÃO

slide-4
SLIDE 4

Futures em Java <= 1.7

slide-5
SLIDE 5

FUTURES EM JAVA <= 1.7

static ExecutorService es = Executors.newCachedThreadPool(); static Integer doubler(Integer n) { return 2 * n; } static Future<Integer> serviceA(Integer n) { return es.submit(() -> { Thread.sleep(1000); return n; }); } static Future<Integer> serviceB(Integer n) { return es.submit(() -> { Thread.sleep(1500); return Double.valueOf(Math.pow(n, 2)).intValue(); }); } static Future<Integer> serviceC(Integer n) { return es.submit(() -> { Thread.sleep(2000); return Double.valueOf(Math.pow(n, 3)).intValue(); }); }

slide-6
SLIDE 6

FUTURES EM JAVA <= 1.7

Integer doubled = doubler(serviceA(10).get()); System.out.println("Couldn't do anything else while the line above was being executed..."); System.out.println("Result: " + serviceB(doubled).get() + " - " + serviceC(doubled).get());

Bloqueia a thread Bloqueia a thread Bloqueia a thread

slide-7
SLIDE 7
  • Desperdício de processamento

Problemas

slide-8
SLIDE 8
  • Desperdício de processamento
  • Baixo nível de composição

Problemas

slide-9
SLIDE 9

E no Java 8?

slide-10
SLIDE 10

FUTURES NO JAVA 8

final CompletableFuture<Integer> doubled = serviceA(10).thenApply(CompletableFutures::doubler); final CompletableFuture<Integer> resultB = doubled.thenCompose(CompletableFutures::serviceB); final CompletableFuture<Integer> resultC = doubled.thenCompose(CompletableFutures::serviceC); CompletableFuture<Void> allFutures = CompletableFuture.allOf(resultB, resultC); allFutures.whenComplete((v, ex) -> { try { System.out.println("Result: " + resultB.get() + " - " + resultC.get()); } catch (Exception e) {} }); System.out.println("Doing other important things...");

slide-11
SLIDE 11

FUTURES NO JAVA 8

final CompletableFuture<Integer> doubled = serviceA(10).thenApply(CompletableFutures::doubler); final CompletableFuture<Integer> resultB = doubled.thenCompose(CompletableFutures::serviceB); final CompletableFuture<Integer> resultC = doubled.thenCompose(CompletableFutures::serviceC); CompletableFuture<Void> allFutures = CompletableFuture.allOf(resultB, resultC); allFutures.whenComplete((v, ex) -> { try { System.out.println("Result: " + resultB.get() + " - " + resultC.get()); } catch (Exception e) {} }); System.out.println("Doing other important things...");

Não bloqueia a thread

slide-12
SLIDE 12

Esses combinadores são familiares?

slide-13
SLIDE 13

STREAMS NO JAVA 8

List<Integer> ns = Arrays.asList(1, 2, 3, 4); Function<Integer, Integer> doubler = (i) -> i * 2; System.out.println(ns.stream().map(doubler).collect(Collectors.toList())); // [2, 4, 6, 8] Function<Integer, Stream<? extends Integer>> toRange = (i) -> IntStream.range(0, i).boxed(); Stream<Integer> combined = ns.stream() .map(doubler) .flatMap(toRange); System.out.println(combined.collect(Collectors.toList())); // [0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7]

slide-14
SLIDE 14

Streams vs Futures

Stream<R> map(Function<? super T, ? extends R> mapper) {…} Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {…} CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {…} CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {…}

slide-15
SLIDE 15

Streams vs Futures

Stream<R> map(Function<? super T, ? extends R> mapper) {…} Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {…} CompletableFuture<U> thenApply (Function<? super T,? extends U> fn) {…} CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {…}

slide-16
SLIDE 16

E se quisermos escrever funções que funcionem com Streams e Futures?

slide-17
SLIDE 17

SEQUENCING FUTURES

CompletableFuture<Collection<Integer>> result = sequence(serviceA(10), serviceB(10), serviceC(10)); // java.util.concurrent.CompletableFuture[10, 100, 1000]

slide-18
SLIDE 18

SEQUENCING FUTURES

static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-19
SLIDE 19

SEQUENCING FUTURES

static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-20
SLIDE 20

SEQUENCING FUTURES

static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-21
SLIDE 21

SEQUENCING FUTURES

static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-22
SLIDE 22

SEQUENCING FUTURES

static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-23
SLIDE 23

SEQUENCING STREAMS

Stream<Integer> s1 = Arrays.asList(1).stream(); Stream<Integer> s2 = Arrays.asList(2).stream(); Stream<Integer> s3 = Arrays.asList(3).stream(); sequenceS(s1, s2, s3) // [[1, 2, 3]]

slide-24
SLIDE 24

SEQUENCING STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); }

slide-25
SLIDE 25

SEQUENCING STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); }

slide-26
SLIDE 26

SEQUENCING STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); }

slide-27
SLIDE 27

SEQUENCING STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); }

slide-28
SLIDE 28

Perceberam alguma semelhança?

slide-29
SLIDE 29

FUTURES VS STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); } static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-30
SLIDE 30

FUTURES VS STREAMS

static <A> Stream<Stream<A>> sequenceS(Stream<A>... cfs) { return Arrays.asList(cfs).stream().reduce( Stream.of(Stream.empty()), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, Stream.of(x)))), (acc, coll) -> acc.flatMap((xs) -> coll.map((x) -> Stream.concat(xs, x)))); } static <A> CompletableFuture<Collection<A>> sequence(CompletableFuture<A>... cfs) { return Arrays.asList(cfs).stream().reduce( CompletableFuture.completedFuture(new ArrayList<>()), (acc, future) -> acc.thenCompose((xs) -> future.thenApply((x) -> { xs.add(x); return xs; })), (a, b) -> a.thenCompose((xs) -> b.thenApply((ys) -> { xs.addAll(ys); return xs; }))); }

slide-31
SLIDE 31

FlatMappable

slide-32
SLIDE 32

FLATMAPPABLE

<M extends FlatMappable, A> M<List<A>> sequence(M<A>... ma) { … }

slide-33
SLIDE 33
  • Java não suporta tipos de alta

espécie (higher kinded types)

  • Tipos de alta espécie são

indispensáveis ao se implementar tais abstrações

Chegando no limite do sistema de tipos

slide-34
SLIDE 34

Colocando nome nos bois

slide-35
SLIDE 35

FlatMappable se chama Monad

trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](a: F[A])(f: A => F[B]): F[B] def map[A, B](a: F[A])(f: A => B): F[B] = bind(a)(b => point(f(b))) }

slide-36
SLIDE 36

FlatMappable se chama Monad

trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](a: F[A])(f: A => F[B]): F[B] def map[A, B](a: F[A])(f: A => B): F[B] = bind(a)(b => point(f(b))) }

Tipos de alta espécie em ação

slide-37
SLIDE 37

MONADS EM SCALA

O Monad de Futures

implicit def FutureMonad: Monad[Future] = new Monad[Future] { def point[A](a: => A) = Future.successful(a) def bind[A, B](a: Future[A])(f: A => Future[B]): Future[B] = a flatMap f }

slide-38
SLIDE 38

MONADS EM SCALA

O Monad de Listas

implicit def ListMonad: Monad[List] = new Monad[List] { def point[A](a: => A) = List(a) def bind[A, B](a: List[A])(f: A => List[B]): List[B] = a flatMap f }

slide-39
SLIDE 39

MONADS EM SCALA

Implementando sequence

def sequence[M[_] : Monad, A](ma: List[M[A]]): M[List[A]] = { ma.foldLeft(Monad[M].point(List(): List[A]))((acc, m) => acc.flatMap((xs) => m.map((x) => xs :+ x)) ) }

slide-40
SLIDE 40

Being abstract is something profoundly different from being vague … The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.

EDSGER W. DIJKSTRA

” “

slide-41
SLIDE 41

MONADS EM SCALA

Sequencing

val resultF: Future[List[Integer]] = sequence(List(serviceA(10), serviceB(10), serviceC(10))) println(Await.result(resultF, Duration(2, "seconds"))) // List(10, 100, 1000) val resultL: List[List[Int]] = sequence(List(List(1,2,3), List(4,5,6), List(7,8,9))) println(resultL) // List(List(1, 4, 7), List(2, 4, 7), List(3, 4, 7), List(1, 5, 7), ...)

slide-42
SLIDE 42

Demais! O quê mais podemos fazer??

slide-43
SLIDE 43

Folding

slide-44
SLIDE 44

FOLDING

List(2, 3, 4).reduce(_+_) //9

slide-45
SLIDE 45

FOLDING

List(2, 3, 4).reduce(_+_) //9 val intFutures = List(Future.successful(1), Future.successful(2), Future.successful(3)) val result: Future[Int] = sequence(intFurures).map((x) => x.reduce(_ + _)) //…Future[9]

slide-46
SLIDE 46

Existe algo em comum?

slide-47
SLIDE 47

Introduzindo Foldable

trait Foldable[F[_]] { self => … def fold[M: Monoid](t: F[M]): M = ??? }

slide-48
SLIDE 48

Introduzindo Monoids

trait Monoid[F] { self => def zero: F def append(f1: F, f2: => F): F }

slide-49
SLIDE 49

Introduzindo Monoids: Ints

implicit def intMonoid: Monoid[Int] = new Monoid[Int] { def zero: Int = 0 def append(f1: Int, f2: => Int): Int = f1 + f2 }

slide-50
SLIDE 50

Introduzindo Monoids: Ints

implicit def intMonoid: Monoid[Int] = new Monoid[Int] { def zero: Int = 0 def append(f1: Int, f2: => Int): Int = f1 + f2 } Foldable[List].fold(List(2, 3, 4))) //9

slide-51
SLIDE 51

Introduzindo Monoids: Futures

slide-52
SLIDE 52

Introduzindo Monoids: Futures

implicit def futureFreeMonoid[A] = new Monoid[Future[List[A]]] { def zero: Future[List[A]] = Future.successful(List()) def append(f1: Future[List[A]], f2: => Future[List[A]]) = for { a1 <- f1 a2 <- f2 } yield a1 ++ a2 }

slide-53
SLIDE 53

Introduzindo Monoids: Futures

implicit def futureFreeMonoid[A] = new Monoid[Future[List[A]]] { def zero: Future[List[A]] = Future.successful(List()) def append(f1: Future[List[A]], f2: => Future[List[A]]) = for { a1 <- f1 a2 <- f2 } yield a1 ++ a2 } Foldable[List].fold(List(Future.successful(2), Future.successful(3), Future.successful(4))) //…Future[9]

slide-54
SLIDE 54

Monad, Foldable e Monoid são apenas

  • começo
slide-55
SLIDE 55

Em Scala, muitas delas já foram implementadas em Scalaz

slide-56
SLIDE 56

A Teoria das Categorias pode ter um impacto grande na criação de bibliotecas

slide-57
SLIDE 57

Being abstract is something profoundly different from being vague … The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.

EDSGER W. DIJKSTRA

” “

slide-58
SLIDE 58

Referências

  • Clojure Reactive Programming - http://bit.ly/cljRp
  • Java 8 CompletableFuture - http://bit.ly/j8Future
  • Java 8 Streams - http://bit.ly/j8stream
  • Category Theory - http://amzn.to/1NfL08U
  • Free Monoids - http://en.wikipedia.org/wiki/Free_monoid
  • Scalaz - https://github.com/scalaz/scalaz
  • Fluokitten (Clojure) - https://github.com/uncomplicate/fluokitten
slide-59
SLIDE 59

Obrigado!

LEONARDO BORGES • SENIOR CLOJURE DEVELOPER • @LEONARDO_BORGES

Q&A

slide-60
SLIDE 60

We are hiring!

LEONARDO BORGES • SENIOR CLOJURE DEVELOPER • @LEONARDO_BORGES