38
Concurrent Application Development using Scala Sergei Semenchuk https://github.com/binjip978/ConcTalk

Concurrent Application Development using Scala

Embed Size (px)

Citation preview

Page 1: Concurrent Application Development using Scala

Concurrent Application Development using

Scala

Sergei Semenchukhttps://github.com/binjip978/ConcTalk

Page 2: Concurrent Application Development using Scala

FP 101

Page 3: Concurrent Application Development using Scala

def withdrawMoney(user: String, password: String, amount: Int): Money = { // some logic Money(amount) }

def buyBook(name: String, cash: Money): Book = { // some logic Book("Functional Programming in Scala") }

val cash = withdrawMoney("user1", "password2", 100) val book = buyBook("Functional Programming in Scala", cash)

println(book)

Page 4: Concurrent Application Development using Scala

trait Try[+T] case class Success[+T](value: T) extends Try[T] case class Failure(e: Throwable) extends Try[Nothing]

val success = Success(100)

success match { case Success(v) => println(v) case Failure(e) => println(s"Error: $e") }

Page 5: Concurrent Application Development using Scala

val v = Try { if (scala.util.Random.nextBoolean() == true) 12 else 1 / 0 }

v match { case Success(v) => println(v) case Failure(e) => println("Error!") }

Page 6: Concurrent Application Development using Scala

def withdrawMoney(user: String, password: String, amount: Int): Try[Money] = { Try(Money(amount)) }

def buyBook(name: String, cash: Money): Try[Book] = { Try(Book("Functional Programming in Scala")) }

withdrawMoney("user1", "password2", 100) match { case Success(cash) => { buyBook("Functional Programming in Scala", cash) match { case Success(book) => println(book) case Failure(e) => println(s"Error occurred: $e") } } case Failure(e) => println(s"Error occurred: $e") }

Page 7: Concurrent Application Development using Scala

case class Money(amount: Int) case class Book(title: String)

def withdrawMoney(user: String, password: String, amount: Int): Try[Money] = { // some logic Try(Money(amount)) }

def buyBook(name: String, cash: Money): Try[Book] = { // some logic Try(Book("Functional Programming in Scala")) }

for { cash <- withdrawMoney("user1", "password2", 100) book <- buyBook("Functional Programming in Scala", cash) } println(book)

Page 8: Concurrent Application Development using Scala

case class Money(amount: Int) case class Book(title: String)

def withdrawMoney(user: String, password: String, amount: Int): Try[Money] = { // some logic Try(Money(amount)) }

def buyBook(name: String, cash: Money): Try[Book] = { // some logic Try(Book("Functional Programming in Scala")) }

val book = withdrawMoney("user1", "password2", 100) .flatMap(cash => buyBook("Functional Programming in Scala", cash))

book.foreach(b => println(b)) }

Page 9: Concurrent Application Development using Scala

trait Option[+A] case class Some[+A](v: A) extends Option[A] case object None extends Option[Nothing]

def unit[A](v: A): Option[A] = { Some(v) }

def flatMap[A, B](op: Option[A])(f: A => Option[B]): Option[B] = op match { case Some(v) => f(v) case None => None }

def map[A, B](op: Option[A])(f: A => B): Option[B] = { flatMap(op)(x => unit(f(x))) }

Page 10: Concurrent Application Development using Scala

The Four Essential Effects In Programming

One Many

Synchronous T/Try[T] Iterable[T]

Asynchronous Future[T] Observable[T]

Page 11: Concurrent Application Development using Scala

Asynchronous Programming with Futures

and Promises

Page 12: Concurrent Application Development using Scala

//def apply[T](b: =>T)(implicit e: ExecutionContext): Future[T]

val f = Future { println("Hello World!") } println(f.isCompleted) Thread.sleep(1000) println(f.isCompleted)

Page 13: Concurrent Application Development using Scala

def getUrlSpec(): Future[List[String]] = Future { val url = "http://www.w3.org/Addressing/URL/url-spec.txt" val f = scala.io.Source.fromURL(url) try { f.getLines().toList } finally { f.close() } }

def find(lines: List[String], keyword: String):String = { lines.zipWithIndex.collect { case (line, n) if (line.contains(keyword)) => (n, line) } mkString("\n") }

val f = getUrlSpec()

f.foreach { case (lines) => println(find(lines, “telnet")) }

Thread.sleep(5000)

Page 14: Concurrent Application Development using Scala

val f: Future[Int] = Future { 1 / 0 }

f onComplete { case Success(v) => println("Surprise!") case Failure(e) => println(s"Error: $e") }

Thread.sleep(1000)

Page 15: Concurrent Application Development using Scala

val f1: Future[Int] = Future { 1345 } val f2: Future[Int] = Future { 2356 } val f3: Future[Int] = Future { 4563 }

val comp1: Future[Int] = f1.flatMap(v1 => f2.flatMap(v2 => f3.map(v3 => v1 + v2 + v3)))

val comp2: Future[Int] = for { v1 <- f1 v2 <- f2 v3 <- f3 } yield v1 + v2 + v3

//comp1 === comp2

comp1.onSuccess { case(x: Int) => println(x) } comp2.onSuccess { case(x: Int) => println(x) }

Thread.sleep(1000) }

Page 16: Concurrent Application Development using Scala

val f1 = Future { 1 } val f2 = Future { 1 / 0 } val f3 = Future { 2 }

val c = for { v1 <- f1 v2 <- f2 v3 <- f3 } yield v1 + v2 + v3

c onComplete { case Success(v) => println(v) case Failure(e) => println(s"error $e") }

Thread.sleep(1000)

Page 17: Concurrent Application Development using Scala

def getRandonName = Future { "John" } def getIdByName(name: String) = Future { 12 } def getDepotIdById(id: Int) = Future { 34 } def getDepotName(id: Int) = Future { "A depot" }

val f = for { name <- getRandonName userId <- getIdByName(name) depotId <- getDepotIdById(userId) depotName <- getDepotName(userId) } yield s"$name from $depotName"

f.onSuccess { case (v) => println(v) }

Thread.sleep(1000)

Page 18: Concurrent Application Development using Scala

def getUSDQuote = Future { 1.2 } def getEURQuote = Future { 0.8 }

val p = for { usd <- getUSDQuote eur <- getEURQuote if (eur > usd) } yield usd

p onFailure { case (e) => println("Error: " + e) }

Thread.sleep(1000)

Page 19: Concurrent Application Development using Scala

val f1: Future[Int] = Future { 1 / 0 }

val f2: Future[Any] = f1.recover { case (exp) => s"error happend: $exp" }

f2.onComplete { case Success(v) => println(s"if success: $v") case Failure(e) => println(s"if failure: $e") }

Thread.sleep(1000)

Page 20: Concurrent Application Development using Scala

val p = Promise[String] val q = Promise[String]

p.future foreach { case x => println(x)} q.future.failed foreach { case e => println(s"error: " + e)}

p.complete(Success("Promise complete")) q.complete(Failure(new Exception))

val z = Promise[Int]

z.future onComplete { case Success(v) => println(v) case Failure(e) => println(s"Error: $e") }

z.complete(Try(1 / 0))

Page 21: Concurrent Application Development using Scala

def first[T](xs: List[Future[T]]): Future[T] = { val p = Promise[T]

for { x <- xs } p.tryCompleteWith(x)

p.future }

val f = first(List(Future{ Thread.sleep(2000); 12 }, Future { new Exception }))

f.foreach { case x => println(x) }

Page 22: Concurrent Application Development using Scala

val urlSpecSize = Future { val url = "http://www.scala-lang.org" scala.io.Source.fromURL(url).size }

// how much we should wait until exception val size = Await.result(urlSpecSize, 10 seconds) println(size)

Page 23: Concurrent Application Development using Scala

Concurrent Programming with Reactive Extensions

Page 24: Concurrent Application Development using Scala

val observable: Observable[String] = Observable.items("A", "B", "C")

observable.subscribe(str => println(str.toLowerCase))

observable.subscribe(str => println(str * 7))

Page 25: Concurrent Application Development using Scala

val o: Observable[Long] = Observable.timer(2 second)

o.subscribe(x => println(x)) o.subscribe(x => println(x + 1000))

Page 26: Concurrent Application Development using Scala

val ex = new RuntimeException val observable: Observable[Int] = Observable.items(0, 1, 2) ++ Observable.error(ex) ++ Observable.items(3, 4)

observable.subscribe( value => println(value), error => println(s"an error occurred: $error") )

Page 27: Concurrent Application Development using Scala

val countries = List("Germany", "US", "Japan") val observable = Observable.from(countries)

observable.subscribe(new Observer[String] {

override def onNext(c: String) = println(s"Nice to live in $c”)

override def onError(e: Throwable) = println(“error!!!")

override def onCompleted() = println("That all list!") })

Page 28: Concurrent Application Development using Scala

// def create(f: Observer[T] => Subscription): Observable[T]

val vms = Observable.apply[String] { obs => obs.onNext("JVM") obs.onNext("LLVM") obs.onNext("Dalvik") obs.onCompleted() Subscription }

vms.subscribe(str => println(str)) }

Page 29: Concurrent Application Development using Scala

val f = Future("Future")

val observable = Observable.apply[String] { obs => f onComplete { case Success(v) => { obs.onNext(v) obs.onCompleted() } case Failure(e) => { obs.onError(e) } }

Subscription }

observable.subscribe(str => println(str))

Page 30: Concurrent Application Development using Scala

def coldObserver(directory: String): Observable[String] = { Observable.apply[String] { obs => val fileMonitor = new FileAlterationMonitor(1000) val fileObs = new FileAlterationObserver(directory) val fileListener = new FileAlterationListenerAdaptor { override def onFileChange(file: java.io.File): Unit = { obs.onNext(file.getName) } }

fileObs.addListener(fileListener) fileMonitor.addObserver(fileObs) fileMonitor.start()

Subscription { fileMonitor.stop() }

} }

Page 31: Concurrent Application Development using Scala

def hotObserver(directory: String): Observable[String] = { val fileMonitor = new FileAlterationMonitor(1000) val fileObs = new FileAlterationObserver(directory) fileMonitor.addObserver(fileObs)

Observable.apply[String] { obs => val fileListener = new FileAlterationListenerAdaptor { override def onFileChange(file: java.io.File): Unit = { obs.onNext(file.getName) } } fileObs.addListener(fileListener) Subscription { fileObs.removeListener( fileListener) } } }

Page 32: Concurrent Application Development using Scala

val odds = Observable.interval(0.5 seconds) .filter(x => x % 2 == 1) .map(x => s"num $x") .take(5)

odds.subscribe(str => println(str))

Page 33: Concurrent Application Development using Scala

def fetchQuote(): Future[String] = Future { blocking { val url = “http://www.iheartquotes.com/api/v1/random?" + "show_permalink=false&show_source=false" Source.fromURL(url).getLines().mkString } }

def fetchQuoteObservable(): Observable[String] = { Observable.from(fetchQuote()) }

def quotes(): Observable[Observable[String]] = { Observable.interval(1 second).take(5).map { n => fetchQuoteObservable().map(txt => s"$n) $txt") } }

val concat: Observable[String] = quotes().concat

concat.subscribe(q => println(q)) / val flatten: Observable[String] = quotes().flatten //

val qs: Observable[String] = for { n <- Observable.interval(1 second).take(5) txt <- fetchQuoteObservable() } yield s"$n) $txt"

qs.subscribe(q => println(q))

Page 34: Concurrent Application Development using Scala

def randomQuote() = Observable.apply[String] { obs => val url = "http://www.iheartquotes.com/api/v1/random?" + "show_permalink=false&show_source=false" obs.onNext(Source.fromURL(url).getLines.mkString) obs.onCompleted()

Subscription }

import Observable._

def errorMessage = items("Retrying...") ++ error(new Exception)

def quoteMessage(): Observable[String] = for { text <- randomQuote() message <- if (text.size < 50) items(text) else errorMessage } yield message

quoteMessage().retry(5).subscribe(str => println(str))

Page 35: Concurrent Application Development using Scala

val status = Observable.items("1", "2") ++ Observable.error(new Exception) val fixedStatus = status.onErrorReturn(e => "exception")

fixedStatus.subscribe(str => println(str))

val continuedStatus = status.onErrorResumeNext(e => Observable.items("4", "5"))

continuedStatus.subscribe(str => println(str))

Page 36: Concurrent Application Development using Scala
Page 37: Concurrent Application Development using Scala
Page 38: Concurrent Application Development using Scala