如何从官方文档解释这个Akka Streams图?

时间:2018-02-06 00:43:06

标签: scala akka akka-stream

我对这个正式托管的示例代码提出了几个问题here

val topHeadSink = Sink.head[Int]
val bottomHeadSink = Sink.head[Int]
val sharedDoubler = Flow[Int].map(_ * 2)

RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((_, _)) { implicit builder =>
  (topHS, bottomHS) =>
  import GraphDSL.Implicits._
  val broadcast = builder.add(Broadcast[Int](2))
  Source.single(1) ~> broadcast.in

  broadcast.out(0) ~> sharedDoubler ~> topHS.in
  broadcast.out(1) ~> sharedDoubler ~> bottomHS.in
  ClosedShape
})
  1. 您何时通过create传递图表?
  2. 为什么topHeadSink, bottomHeadSink通过create传入,但sharedDoubler不是?他们之间有什么区别?

    1. 您何时需要builder.add
    2. 我可以在没有builder.add的情况下在图表外创建广播吗?如果我在图中添加了几个流,我是否应该通过builder.add添加流量?有时我们需要builder.add,有时我们不需要,这是非常令人困惑的。

      更新

      我觉得这仍然令人困惑:

      这些方法之间的区别在于使用builder.add(...)导入会忽略导入图形的具体化值,而通过工厂方法导入则允许包含它。

      topHS, bottomHS是从create导入的,因此他们会保留其物化价值。如果我builder.add(topHS)怎么办?

      你如何解释sharedDoubler:它是否具有物化价值?如果我使用builder.add怎么办?

      1. 这是什么意思,((_,_))的{​​{1}}?
      2. 它看起来像我们需要的样板,但我不确定它是什么。

1 个答案:

答案 0 :(得分:0)

  
      
  1. 您何时通过create?
  2. 传递图表   

如果要获取传递给create工厂方法的图表的具体化值。您问题中RunnableGraph的类型为RunnableGraph[(Future[Int], Future[Int])],表示图表的具体化值为(Future[Int], Future[Int])

val g = RunnableGraph.fromGraph(...).run() // (Future[Int], Future[Int])
val topHeadSinkResult    = g._1 // Future[Int]
val bottomHeadSinkResult = g._2 // Future[Int]

现在考虑以下变体,它定义了图形内部的接收器并丢弃了具体化的值:

val g2 = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder =>
  import GraphDSL.Implicits._

  val topHeadSink = Sink.head[Int]
  val bottomHeadSink = Sink.head[Int]
  val broadcast = builder.add(Broadcast[Int](2))

  Source.single(1) ~> broadcast.in
  broadcast.out(0) ~> sharedDoubler ~> topHeadSink
  broadcast.out(1) ~> sharedDoubler ~> bottomHeadSink
  ClosedShape
}).run() // NotUsed

g2的值为NotUsed

  
      
  1. 你什么时候需要builder.add?
  2.   

图表的所有组件都必须添加到构建器中,但~>运算符的变体添加了最常用的组件 - 例如Source和{{1} - 给掩护下的建造者。但是,执行扇入(例如Flow)或扇出(例如Merge)的联结操作必须明确传递给Broadcast如果您使用的是图形DSL。

请注意,对于简单的图形,您可以使用联结而无需使用Graph DSL。以下是documentation

中的示例
builder.add
  
      
  1. 这是什么意思? val sendRmotely = Sink.actorRef(actorRef, "Done") val localProcessing = Sink.foreach[Int](_ => /* do something usefull */ ()) val sink = Sink.combine(sendRmotely, localProcessing)(Broadcast[Int](_)) Source(List(0, 1, 2)).runWith(sink) 的{​​{1}}?
  2.   

这是一个curried参数,用于指定要保留的物化值。在这里使用((_,_))与:

相同
GraphDSL.create(topHeadSink, bottomHeadSink)((_, _))

换句话说,((_, _))在此上下文中是val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, b) => (t, b)) { implicit builder => (topHS, bottomHS) => ... }).run() // (Future[Int], Future[Int]) 的简写,它保留了传入的两个接收器的相应具体化值。例如,如果您只想保留((_, _))的具体化值,您可以将调用更改为以下内容:

((t, b) => (t, b))