Scala 如何对ActorPublisher进行背压
我写了一些样本来了解akka流和背压。我想看看缓慢的消费者反压力是如何影响AkkaPublisher的 我的代码如下Scala 如何对ActorPublisher进行背压,scala,akka,reactive-programming,akka-stream,reactive-streams,Scala,Akka,Reactive Programming,Akka Stream,Reactive Streams,我写了一些样本来了解akka流和背压。我想看看缓慢的消费者反压力是如何影响AkkaPublisher的 我的代码如下 class DataPublisher extends ActorPublisher[Int] { import akka.stream.actor.ActorPublisherMessage._ var items: List[Int] = List.empty def receive = { case s: String => pr
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")
}
}
及
其中,接收器是一个用户,具有模拟慢速用户的睡眠。而且publisher始终不停地生成数据
-编辑-
我的问题是当需求为0时,编程缓冲数据。我如何利用背压来降低发行速度
差不多
throttledSource().buffer(10, OverflowStrategy.backpressure).runWith(throttledSink())
这不会影响发布服务器,其缓冲区将继续运行
谢谢,
Sajith这可以通过中间步骤实现:
这可以通过中间步骤来实现: 不要使用ActorPublisher 首先,不要使用ActorPublisher-它是一个非常低级且不推荐使用的API。我们决定反对,因为用户不应该在Akka流中处理如此低级别的抽象 其中一件棘手的事情正是您要问的——如果开发人员使用此API,那么处理背压完全掌握在编写ActorPublisher的开发人员手中。因此,您必须接收Requestn消息,并确保发送的元素不会超过您收到的请求。在中指定了此行为,然后必须正确实施。基本上,您已经接触到反应流的所有复杂性,这是一个完整的规范,有许多边缘案例-免责声明:我曾经/现在是开发反应流以及Akka流的一部分 显示背压如何在图中显示 其次,要构建定制阶段,您应该使用为其设计的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。Akka Streams处理需求管理,如果下游发出需求信号,它将自动调用onPull,如果没有需求,它将不会调用onPull,这意味着下游正在向该阶段施加背压。不要使用ActorPublisher
首先,不要使用ActorPublisher-它是一个非常低级且不推荐使用的API。我们决定反对,因为用户不应该在Akka流中处理如此低级别的抽象
其中一件棘手的事情正是您要问的——如果开发人员使用此API,那么处理背压完全掌握在编写ActorPublisher的开发人员手中。因此,您必须接收Requestn消息,并确保发送的元素不会超过您收到的请求。在中指定了此行为,然后必须正确实施。基本上,您已经接触到反应流的所有复杂性,这是一个完整的规范,有许多边缘案例-免责声明:我曾经/现在是开发反应流以及Akka流的一部分
显示背压如何在图中显示
其次,要构建定制阶段,您应该使用为其设计的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。Akka Streams处理需求管理,如果下游发出需求信号,它将自动调用onPull,如果没有需求,它将不会调用onPull,这意味着下游正在向该阶段施加背压。谢谢,这是可行的。但后来我意识到我关心的不是缓冲,而是背压。因为即使我缓冲流,发布者的缓冲区也会不断增长。为了避免这种情况,我需要对出版商施加压力,使其放慢速度。我该怎么做呢。我已经更新了问题。很抱歉让您困惑这很有帮助,但它不会减少演员发布者的邮箱,即dataPublisherRef本身。谢谢,这很有效。但后来我意识到我关心的不是缓冲,而是背压。因为即使我缓冲流,发布者的缓冲区也会不断增长。为了避免这种情况,我需要对出版商施加压力,使其放慢速度。我该怎么做呢。我已经更新了问题。很抱歉让您困惑这很有帮助,但它不会减少actor publisher的邮箱,即dataPublisherRef本身。谢谢Konrad,您的解释澄清了我与actor publisher之间的许多问题。我
谢谢康拉德,你的解释澄清了我和ActorPublisher之间的很多问题。我会更多地测试图表阶段。
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)
}
}