问题描述
我正在尝试了解 Keep 在 Akka 流中的工作方式.阅读 保持在 akka 流中意味着什么 中的答案,我明白它有助于控制我们从具体化器的左侧/右侧/两侧获得结果.但是,我仍然无法构建一个示例,因为我可以更改左/右的值并获得不同的结果.
I am trying to wrap my head around how Keep works in Akka streams. Reading answers in What does Keep in akka stream mean, I understand that it helps to control we get the result from the left/right/both sides of the materializer. However, I still can't build an example were I can change the value of left/right and get different results.
例如
implicit val system: ActorSystem = ActorSystem("Playground")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val sentenceSource = Source(List(
"Materialized values are confusing me",
"I love streams",
"Left foo right bar"
))
val wordCounter = Flow[String].fold[Int](0)((currentWords, newSentence) => currentWords + newSentence.split(" ").length)
val result = sentenceSource.viaMat(wordCounter)(Keep.left).toMat(Sink.head)(Keep.right).run()
val res = Await.result(result, 2 second)
println(res)
在这个例子中,如果我将值从保持左移到保持右移,我仍然得到相同的结果.有人可以向我提供一个基本示例,其中将 keep 更改为左/右/两个值会导致不同的结果吗?
In this example if I change values from keep left to keep right, I still get the same result. Can someone provide me with a basic example where changing keep to left/right/both values results in a different outcome?
推荐答案
在你的例子中,因为:
sentenceSource: akka.stream.scaladsl.Source[String,akka.NotUsed] = ???
wordCounter: akka.stream.scaladsl.Flow[String,Int,akka.NotUsed] = ???
两者都有 NotUsed
作为它们的具体化(表明它们没有有用的具体化),
both have NotUsed
as their materialization (indicating that they don't have a useful materialization),
sentenceSource.viaMat(wordCounter)(Keep.right)
sentenceSource.viaMat(wordCounter)(Keep.left)
具有相同的物化.但是,由于 Sink.head[T]
实现了 Future[T]
,因此更改组合器显然会产生影响
have the same materialization. However, since Sink.head[T]
materializes to Future[T]
, changing the combiner clearly has an impact
val intSource = sentenceSource.viaMat(wordCounter)(Keep.right)
val notUsed = intSource.toMat(Sink.head)(Keep.left)
// akka.stream.scaladsl.RunnableGraph[akka.NotUsed]
val intFut = intSource.toMat(Sink.head)(Keep.right)
// akka.stream.scaladsl.RunnableGraph[scala.concurrent.Future[Int]]
notUsed.run // akka.NotUsed
intFut.run // Future(Success(12))
Source
中的大部分源代码都实现了 NotUsed
并且几乎所有常见的 Flow
操作符也实现了,所以 toMat(someSink)(Keep.right)
(或等效的 .runWith(someSink)
)比使用 Keep.left
或 Keep 更普遍.both
.源/流物化最常见的用例是提供某种控制平面,例如:
Most of the sources in Source
materialize to NotUsed
and nearly all of the common Flow
operators do as well, so toMat(someSink)(Keep.right)
(or the equivalent .runWith(someSink)
) is far more prevalent than using Keep.left
or Keep.both
. The most common usecases for source/flow materialization are to provide some sort of control plane, such as:
import akka.Done
import akka.stream.{ CompletionStrategy, OverflowStrategy }
import system.dispatcher
val completionMatcher: PartialFunction[Any, CompletionStrategy] = { case Done => CompletionStrategy.draining }
val failureMatcher: PartialFunction[Any, Throwable] = { case 666 => new Exception("""m/""") }
val sentenceSource = Source.actorRef[String](completionMatcher = completionMatcher, failureMatcher = failureMatcher, bufferSize = 100, overflowStrategy = OverflowStrategy.dropNew)
// same wordCounter as before
val stream = sentenceSource.viaMat(wordCounter)(Keep.left).toMat(Sink.head)(Keep.both) // akka.stream.scaladsl.RunnableGraph[(akka.actor.ActorRef, scala.concurrent.Future[Int])]
val (sourceRef, intFut) = stream.run()
sourceRef ! "Materialized values are confusing me"
sourceRef ! "I love streams"
sourceRef ! "Left foo right bar"
sourceRef ! Done
intFut.foreach { result =>
println(result)
system.terminate()
}
在这种情况下,我们使用 Keep.left
来传递 sentenceSource
的物化值,然后使用 Keep.both
来获得两者物化值和 Sink.head
.
In this case, we use Keep.left
to pass through sentenceSource
's materialized value and then Keep.both
to get both that materialized value and that of Sink.head
.
这篇关于Akka Stream 的 Keep right/left/both 如何导致不同的输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!