Future and explicit ExecutionContext by using for-comprehensions: map() and flatMap()

363 views
Skip to first unread message

Martin Senne

unread,
May 21, 2014, 12:24:06 PM5/21/14
to scala...@googlegroups.com
Hi all,

According to Bruno's post Future & ExecutionContext 
I'm still not clear, if there is a way to use for-comprehension and explicit specified ExecutionContext together?

object RealFun {
  def computationA: String = {
    "asdf" + "ibjmaretg"
  }

  def computationB: Int = {
    (25 * 342 + 12) * 2
  }

  def computationC(x: String, y: Int): Double = {
    (x.length + y) * 0.3
  }

  def main(args: Array[String]) : Unit = {
    implicit val defaultEC = ExecutionContext.Implicits.global
    val ec1:ExecutionContext = ...
    val ec2:ExecutionContext = ...
    val ec3:ExecutionContext = ...

    val fx5 = Future(computationA)(ec1)
    val fy5 = Future(computationB)(ec1)

    // 1. What I really want is 
    // val fz5 = fx5.flatMap(x1 => fy5.map( y1 => computationC(x1, y1) )(ec3))(ec2)

    // 2. What I do, but which still uses defaultEC for flatMap
    val fz5 = (for {
      x1 <- fx5
      y1 <- fy5 // requires implicit execution context
    } yield computationC(x1, y1))(ec2)

    // 2. in desugared version
    // val fz5 = fx5.flatMap(x1 => fy5.map( y1 => computationC(x1, y1) )(defaultEC))(ec2)

    // Can 1. be expressed by a for comprehension?
  }
}

Many thanks in advance and cheers,

Martin

Som Snytt

unread,
May 21, 2014, 1:32:38 PM5/21/14
to Martin Senne, scala-user
I was thinking: for (x <- a ; implicit n = ec2 ; y <- b) yield z



--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Martin Senne

unread,
May 22, 2014, 4:33:19 AM5/22/14
to scala...@googlegroups.com, Martin Senne
Hi Som, hi all,

@Som: 
  1. Thanks for pointing out the issue ticket. 
  2. Implicits in for-comprehensions could be one solution. But still are not the optimum.
@All:

Is there really no way to express this 
    fx5.flatMap(x1 => fy5.map( y1 => computationC(x1, y1) )(ec3))(ec2)
as a for-comprehension?

Refering to my inital example, I want to run
  • computationA and computationB to run on execution context 1
  • flatMap on execution context 2
  • map and computationC in execution context 3

Cheers,

Martin

Som Snytt

unread,
May 22, 2014, 2:41:30 PM5/22/14
to Martin Senne, scala-user
This got down-voted on SO at a time when I was very sensitive to down-votes (since then, I don't much care), so take the usual grain of salt.  I only mention it because you said "is there really no way."

Running it shows that x and y are evaluated on different pools.

apm@mara:~/tmp$ scalac impctx.scala && scala impctx.Test
ForkJoinPool-1-worker-11
ForkJoinPool-1-worker-13
pool-1-thread-1
pool-2-thread-1
pool-3-thread-1
12


The idea is to update a var as a side effect of a guard.

import concurrent._
import duration._
import Duration._
import ExecutionContext.Implicits._
import java.util.concurrent.{ Executors }

object Test extends App {
  val ec2 = ExecutionContext fromExecutorService Executors.newCachedThreadPool
  val ec3 = ExecutionContext fromExecutorService Executors.newCachedThreadPool
  val ec4 = ExecutionContext fromExecutorService Executors.newCachedThreadPool
  //fx5.flatMap(x1 => fy5.map( y1 => computationC(x1, y1) )(ec3))(ec2)
  // given a couple of futures on default ctx, have the completion of
  // f1 run on ctx2, and the computation using the two results on ctx3

  def ? = Console println Thread.currentThread.getName

  val f1 = Future { ? ; 3 }
  val f2 = Future { ? ; 4 }
  /* usually,
  val res =
    for {
      a <- f1
      b <- f2
    } yield {
      a * b
    }
   */
  implicit var ctx = ec2
  val res =
    for {
      a <- f1
      x = { ? ; a }
      if { ctx = ec3 ; true }
      b <- f2
      y = { ? ; b }
      if { ctx = ec4 ; true }
    } yield {
      ?
      x * y
    }
  Console println Await.result(res, Inf)
  ec2.shutdownNow()
  ec3.shutdownNow()
  ec4.shutdownNow()
}


This is the original SO text.

/*
That's a good one, but the answer is no, all you get to work with is a pattern.

This is not an answer, but you can sneak exprs into a guard. (Cf Responder.exec().)

Hence, and please don't hate me:

scala> val xs = List(1,2,3)
scala> def bar(implicit i: Int) = Some(i+1)
scala> implicit var imp: Int = 0
scala> for { a<-xs; if { imp=a; true }; b<-bar } yield b
res6: List[Int] = List(2, 3, 4)

Also not pretty, and also not an answer, but gives you a new scope for the implicit:

// for (a <- xs; implicit x = a; b = bar)  // not b <- bar
(a, b) <- for (a <- xs) yield { implicit val x = a; (a, bar) }

// if you don't need a:
//b <- for (a <- xs) yield { implicit val x = a; bar }

Thinking about how val defs work here:

//a <- xs
//implicit i = a
// if allowed, would desugar to
//(a, i) <- for (x@a <- xs) yield { implicit val x0@i=a; (x, x0) }
//b <- bar

ceci n'est pas une réponse.
 */


Reply all
Reply to author
Forward
0 new messages