我正在Scala第一次使用Futures,正在研究使用flatMap组合器的例子;我一直在关注这个讨论:
http://docs.scala-lang.org/overviews/core/futures.html
具体来说,这个例子:
val usdQuote = future { connection.getCurrentValue(USD) }
val chfQuote = future { connection.getCurrentValue(CHF) }
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
purchase onSuccess {
case _ => println("Purchased " + amount + " CHF")
}
被翻译成:
val purchase = usdQuote flatMap {
usd =>
chfQuote
.withFilter(chf => isProfitable(usd, chf))
.map(chf => connection.buy(amount, chf))
}
我有点麻烦抓到的是如何以及何时执行flatMap?
据我所知,usdQuote和chfQuote是在“某个时间”由“某个线程”执行的,并且他们注册的回调函数被调用,问题是:
a)usdQuote和chfQuote是否同时执行? (我很确定他们是。)
b)flatMap如何将Future useQuote的值分配给usd?如同在操作usdQuote完成时调用它?
c)执行'flatMap'和'map'操作的线程(可能是上一个问题的后续操作)。
干杯。
答案 0 :(得分:10)
a)当你创建它们时,你已经开始对范围内的隐式ExecutionContext执行它们,因此它们可能同时运行,因为它取决于执行它们的方式。
b)它并没有真正分配这样的值,但实现使用onComplete方法使得一旦达到结果就会触发您传递的函数。目前,这应链接到我所指的flatMap方法:https://github.com/scala/scala/blob/v2.11.2/src/library/scala/concurrent/Future.scala#L246
c)这些是通过前面提到的ExecutionContext运行的,还要考虑如果这些Future实例可以在不同的ExecutionContexts上运行,那么for-comprehension的部分可以在不同的线程池上运行。
答案 1 :(得分:2)
我面临着同样的问题......我发现了有关复合的有用this一般性解释。可能有帮助:
对于集合的map
,flatMap
和filter
操作,for-comprehension是语法糖。
一般表格为for (s) yield e
s
是一系列生成器和过滤器p <- e
是一个生成器if f
是一个过滤器{ s }
代替( s )
e
是生成的集合的元素示例1:
// list all combinations of numbers x and y where x is drawn from
// 1 to M and y is drawn from 1 to N
for (x <- 1 to M; y <- 1 to N)
yield (x,y)
相当于
(1 to M) flatMap (x => (1 to N) map (y => (x, y)))
for-expression看起来像传统的for循环,但内部工作方式不同
for (x <- e1) yield e2
已翻译为e1.map(x => e2)
for (x <- e1 if f) yield e2
已翻译为for (x <- e1.filter(x => f)) yield e2
for (x <- e1; y <- e2) yield e3
已翻译to e1.flatMap(x => for (y <- e2) yield e3)
这意味着只要您定义map,flatMap和filter
,就可以对自己的类型使用for-understanding。示例2:
for {
i <- 1 until n
j <- 1 until i
if isPrime(i + j)
} yield (i, j)
相当于
for (i <- 1 until n; j <- 1 until i if isPrime(i + j))
yield (i, j)
相当于
(1 until n).flatMap(i => (1 until i).filter(j => isPrime(i + j)).map(j => (i, j)))
答案 2 :(得分:2)
您还可以在&#34; Scala notes – Futures – 3 (Combinators and Async)&#34;中有一个很好的并发Future
执行示例。来自 Arun Manivannan 。
我们的
Futures
需要并行运行 为了实现这一点,我们需要做的就是提取Future
块并单独声明它们。
代码:
val oneFuture: Future[Int] = Future {
Thread.sleep(1000)
1
}
val twoFuture: Future[Int] = Future {
Thread.sleep(2000)
2
}
val threeFuture: Future[Int] = Future {
Thread.sleep(3000)
3
}
作为-理解强>:
def sumOfThreeNumbersParallelMapForComprehension(): Future[Int] = for {
oneValue <- oneFuture
twoValue <- twoFuture
threeValue <- threeFuture
} yield oneValue + twoValue + threeValue
<强> flatmap 强>:
def sumOfThreeNumbersParallelMap(): Future[Int] = oneFuture.flatMap { oneValue =>
twoFuture.flatMap { twoValue =>
threeFuture.map { threeValue =>
oneValue + twoValue + threeValue
}
}
}
测试:
describe("Futures that are executed in parallel") {
it("could be composed using for comprehensions") {
val futureCombinators = new FutureCombinators
val result = timed(Await.result(futureCombinators.sumOfThreeNumbersParallel(), 4 seconds))
result shouldBe 6
}
}
它确实说明了:
Future
是某种类型的值的容器(即它接受一个类型作为参数,没有它就不能存在)。
您可以拥有Future[Int]
或Future[String]
或Future[AwesomeClass]
- 您不能只拥有简单Future
。
一个奇特的术语是类型构造函数 要进行比较,List
是一个类型构造函数(以及Monad)List
是Int,
String
或任何其他类型的值的容器。不存在包含类型的List
/Future
。- 醇>
Future
具有flatMap
和unit
个函数(以及相应的map
函数)。