Scala 如何对ActorPublisher进行背压

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

我写了一些样本来了解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")
  }
}

其中,接收器是一个用户,具有模拟慢速用户的睡眠。而且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)
  }
}