我正在写几个样本来了解akka流和背压。我正在试图看一个缓慢的消费者背压是一个AkkaPublisher
我的代码如下。
class DataPublisher extends ActorPublisher[Int] {
import akka.stream.actor.ActorPublisherMessage._
var items: List[Int] = List.empty
def receive = {
case s: String =>
println(s"Producer buffer size ${items.size}")
if (totalDemand == 0)
items = items :+ s.toInt
else
onNext(s.toInt)
case Request(demand) =>
if (demand > items.size) {
items foreach (onNext)
items = List.empty
}
else {
val (send, keep) = items.splitAt(demand.toInt)
items = keep
send foreach (onNext)
}
case other =>
println(s"got other $other")
}
}
和
Source.fromPublisher(ActorPublisher[Int](dataPublisherRef)).runWith(sink)
其中,接收器是具有睡眠的用户,以模拟慢速消费者。并且发布者不断地生成数据。
- EDIT-- 我的问题是,当需求为0时,以编程方式缓冲数据。如何利用背压来减慢发布者的速度
像
这样的东西throttledSource().buffer(10, OverflowStrategy.backpressure).runWith(throttledSink())
这不会影响发布者及其缓冲区继续运行。
谢谢, Sajith
答案 0 :(得分:3)
首先,请勿使用ActorPublisher
- 这是一个非常低级且已弃用的API 。我们决定弃用,因为用户不应该在Akka Streams中进行如此低级别的抽象。
其中一个棘手的问题正是你要问的问题 - 如果他们使用这个API ,那么处理backpressure完全掌握在编写ActorPublisher的开发人员手中。因此,您必须收到Request(n)
消息,并确保从不发出更多信号,而不是您的请求。此行为在Reactive Streams Specification中指定,然后您必须正确实现。基本上,您已经暴露于Reactive Streams的所有复杂性(这是一个完整的规范,包含许多边缘情况 - 免责声明:我是开发Reactive Streams以及Akka Streams的一部分。)
其次,要构建自定义阶段,您应该使用为其设计的API:GraphStage
。请注意,这样的舞台也是相当低的水平。通常情况下,Akka Streams的用户不需要编写自定义阶段,但是如果他们实现内置阶段无法提供的某些逻辑,那么编写自己的阶段是绝对的期望和罚款。
这是来自Akka代码库的简化过滤器实现:
case class Filter[T](p: T ⇒ Boolean) extends SimpleLinearGraphStage[T] {
override def initialAttributes: Attributes = DefaultAttributes.filter
override def toString: String = "Filter"
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
new GraphStageLogic(shape) with OutHandler with InHandler {
override def onPush(): Unit = {
val elem = grab(in)
if (p(elem)) push(out, elem)
else pull(in)
}
// this method will NOT be called, if the downstream has not signalled enough demand!
// this method being NOT called is how back-pressure manifests in stages
override def onPull(): Unit = pull(in)
setHandlers(in, out, this)
}
}
正如您所看到的,您可以获得简单的回调,例如onPush
和onPull
,而不是自己实现整个Reactive Streams逻辑和规则(这很难)。 Akka Streams处理需求管理,如果下游已发出需求信号,它将自动调用onPull
,如果没有需求,它将不会调用它 - 这意味着下游正在向此阶段施加背压。
答案 1 :(得分:2)
这可以通过中间Flow.buffer
:
With()