View
174
Download
4
Category
Preview:
Citation preview
Concurrent Application Development using
Scala
Sergei Semenchukhttps://github.com/binjip978/ConcTalk
FP 101
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)
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") }
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!") }
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") }
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)
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)) }
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))) }
The Four Essential Effects In Programming
One Many
Synchronous T/Try[T] Iterable[T]
Asynchronous Future[T] Observable[T]
Asynchronous Programming with Futures
and Promises
//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)
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)
val f: Future[Int] = Future { 1 / 0 }
f onComplete { case Success(v) => println("Surprise!") case Failure(e) => println(s"Error: $e") }
Thread.sleep(1000)
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) }
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)
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)
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)
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)
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))
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) }
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)
Concurrent Programming with Reactive Extensions
val observable: Observable[String] = Observable.items("A", "B", "C")
observable.subscribe(str => println(str.toLowerCase))
observable.subscribe(str => println(str * 7))
val o: Observable[Long] = Observable.timer(2 second)
o.subscribe(x => println(x)) o.subscribe(x => println(x + 1000))
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") )
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!") })
// 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)) }
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))
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() }
} }
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) } } }
val odds = Observable.interval(0.5 seconds) .filter(x => x % 2 == 1) .map(x => s"num $x") .take(5)
odds.subscribe(str => println(str))
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))
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))
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))
Recommended