我使用mapAync(1)
的代码无法正常运行。但是当我使用mapAsync(1)
将map
更改为Await.result
时,它就可以了。所以我有一个问题。
以下(A) Use map
和(B) use mapAsync(1)
会随时产生相同的结果吗?
// (A) Use map
someSource
.map{r =>
val future = makeFuture(r) // returns the same future if r is the same
Await.result(future, Duration.Inf)
}
// (B) Use mapAsync(1)
someSource
.mapAsync(1){r =>
val future = makeFuture(r) // returns the same future if r is the same
future
}
实际上,我想粘贴我的真实代码,但是粘贴时间太长而且我的原始阶段有一些依赖性。
答案 0 :(得分:3)
虽然在语义上两个流的类型最终相同(Source[Int, NotUsed]
),但示例(A)
中显示的样式非常糟糕 - 请不要阻止({{1}内部流。
此类案例正是Await
的用例。您的操作返回mapAsync
,并且您希望在将来完成后将该值向下推送到流中。请注意,mapAsync中有无阻塞,它会调度回调以在内部推送未来值,并在完成后执行此操作。
要回答关于"他们做同样事情的问题?",技术上是,但第一个会导致您正在运行的线程池中的性能问题,避免地图+阻止时mapAsync可以完成这项工作。
答案 1 :(得分:1)
这些调用在语义上非常相似,尽管使用Await
进行阻塞可能不是一个好主意。这些调用的类型签名当然是相同的(Source[Int, NotUsed]
),并且在许多情况下这些调用将产生相同的结果(阻塞)。例如,以下内容包括计划期货和失败的非默认监管策略,对于内部有Await和mapAsync的地图都给出了相同的结果:
import akka.actor._
import akka.stream.ActorAttributes.supervisionStrategy
import akka.stream.Supervision.resumingDecider
import akka.stream._
import akka.stream.scaladsl._
import scala.concurrent._
import scala.concurrent.duration._
import scala.language.postfixOps
object Main {
def main(args: Array[String]) {
implicit val system = ActorSystem("TestSystem")
implicit val materializer = ActorMaterializer()
import scala.concurrent.ExecutionContext.Implicits.global
import system.scheduler
def makeFuture(r: Int) = {
akka.pattern.after(2 seconds, scheduler) {
if (r % 3 == 0)
Future.failed(new Exception(s"Failure for input $r"))
else
Future(r + 100)
}
}
val someSource = Source(1 to 20)
val mapped = someSource
.map { r =>
val future = makeFuture(r)
Await.result(future, Duration.Inf)
}.withAttributes(supervisionStrategy(resumingDecider))
val mappedAsync = someSource
.mapAsyncUnordered(1) { r =>
val future = makeFuture(r)
future
}.withAttributes(supervisionStrategy(resumingDecider))
mapped runForeach println
mappedAsync runForeach println
}
}
您的上游代码可能以某种方式依赖地图调用中的阻止行为。您能否对您所看到的问题进行简洁的再现?