Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 有没有更高级的方法来编写自定义GraphStage?_Scala_Akka_Akka Stream - Fatal编程技术网

Scala 有没有更高级的方法来编写自定义GraphStage?

Scala 有没有更高级的方法来编写自定义GraphStage?,scala,akka,akka-stream,Scala,Akka,Akka Stream,我试图了解一些较新的阿卡溪流。我有一个自定义的FanOutShape2形状,它做的事情非常简单:输入(布尔,Option[a_Thing]),然后决定是否将流路由到out0或out1(通过或失败),如下所示: object PassFilter { type FilterShape = FanOutShape2[(Boolean, Option[OutputWrapper]), OutputWrapper, akka.NotUsed] } import PassFilter._ case

我试图了解一些较新的阿卡溪流。我有一个自定义的FanOutShape2形状,它做的事情非常简单:输入(布尔,Option[a_Thing]),然后决定是否将流路由到out0或out1(通过或失败),如下所示:

object PassFilter {
  type FilterShape = FanOutShape2[(Boolean, Option[OutputWrapper]), OutputWrapper, akka.NotUsed]
}
import PassFilter._

case class PassFilter()(implicit asys: ActorSystem) extends GraphStage[FilterShape] {
  val mergedIn: Inlet[(Boolean, Option[OutputWrapper])] = Inlet("Merged")
  val outPass: Outlet[OutputWrapper] = Outlet("Pass")
  val outFail: Outlet[akka.NotUsed] = Outlet("Fail")

  override val shape: FilterShape = new FanOutShape2(mergedIn, outPass, outFail)

  override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
    override def preStart(): Unit = pull(mergedIn)
    setHandler(mergedIn, new InHandler {
      override def onPush(): Unit = {
        val (passedPrivacy, outWrapper) = grab(mergedIn)
        if (!passedPrivacy || outWrapper.isEmpty)
          push(outFail, akka.NotUsed)
        else
          push(outPass, outWrapper.get)
        pull(mergedIn)
      }
      override def onUpstreamFinish(): Unit = {} // necessary for some reason!
    })
    setHandler(outPass, eagerTerminateOutput)
    setHandler(outFail, eagerTerminateOutput)
  }
}

这个基本的想法是可行的,我可以看到它给了我完全控制流程的可能性,但是对于这个超级琐碎的决策逻辑,有没有一种更简单、更高级的方法来创建一个可以包含在我的GraphDSL中的“小部件”?

这个答案基于
akka stream
版本
2.4.2-RC1
。其他版本中的API可能略有不同。依赖项可由以下人员使用:


您可以轻松地创建自己对该逻辑的抽象。您可以将其添加为类型参数,而不是硬编码
PassFilter
类的类型。您可以将其作为构造函数参数传递,而不是硬编码确定输出端口的函数。通过这样做,您将收到一个可以连接到任意流的可重用组件。幸运的是,Akka已经提供了这样一个组件。它被称为分区:

val shape = GraphDSL.create() { implicit b ⇒
  import GraphDSL.Implicits._

  val first = b.add(Sink.foreach[Int](elem ⇒ println("even:\t" + elem)))
  val second = b.add(Sink.foreach[Int](elem ⇒ println("odd:\t" + elem)))
  val p = b.add(Partition[Int](2, elem ⇒ if (elem%2 == 0) 0 else 1))

  p ~> first
  p ~> second

  SinkShape(p.in)
}
Source(1 to 5).to(shape).run()

/*
This should print:
odd:    1
even:   2
odd:    3
even:   4
odd:    5
*/
分区
组件还将许多输出端口作为参数,以使其更加可重用。使用
~>
符号,您可以将输出端口连接到其他组件,我在示例中就是这样做的。当然,您可以省略该选项,并通过
FanOutShape2
组件返回两个输出端口

val shape = GraphDSL.create() { implicit b ⇒
  import GraphDSL.Implicits._

  val first = b.add(Sink.foreach[Int](elem ⇒ println("even:\t" + elem)))
  val second = b.add(Sink.foreach[Int](elem ⇒ println("odd:\t" + elem)))
  val p = b.add(Partition[Int](2, elem ⇒ if (elem%2 == 0) 0 else 1))

  p ~> first
  p ~> second

  SinkShape(p.in)
}
Source(1 to 5).to(shape).run()

/*
This should print:
odd:    1
even:   2
odd:    3
even:   4
odd:    5
*/