Scala 如何解释官方文件中的Akka流图?

Scala 如何解释官方文件中的Akka流图?,scala,akka,akka-stream,Scala,Akka,Akka Stream,对于这个正式托管的示例代码,我有几个问题: 何时通过创建传入图形 为什么topHeadSink、bottomHeadSink是通过create传入的,而sharedDoubler不是?他们之间有什么区别 何时需要builder.add 我是否可以在没有builder.add的情况下在图形外部创建广播?如果我在图中添加了几个流,我是否也应该通过builder.add添加流?有时我们需要builder.add,有时我们不需要,这是非常令人困惑的 更新 我觉得这仍然令人困惑: 这些方法之间的区别在于,

对于这个正式托管的示例代码,我有几个问题:

  • 何时通过
    创建
    传入图形
  • 为什么
    topHeadSink、bottomHeadSink
    是通过create传入的,而
    sharedDoubler
    不是?他们之间有什么区别

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

    更新

    我觉得这仍然令人困惑:

    这些方法之间的区别在于,使用
    builder.add(…)
    导入会忽略导入图形的物化值,而通过factory方法导入则允许包含该值

    topHS、bottomHS
    是从
    create
    导入的,因此它们将保留其物化值。如果我执行
    builder.add(topHS)
    ,该怎么办

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

  • 这是什么意思,
    GraphDSL.create(topHeadSink,bottomHeadSink)((,))的
    (((,))
  • 它看起来像是我们需要的样板,但我不确定它是什么

  • 什么时候通过create传入图形
  • 当您想要获得传递给
    create
    factory方法的图形的物化值时。您问题中的
    RunnableGraph
    类型是
    RunnableGraph[(未来[Int],未来[Int])]
    ,这意味着图形的物化值是
    (未来[Int],未来[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
    的值为
    未使用

  • 何时需要builder.add
  • 图形的所有组件都必须添加到生成器中,但是有一些操作符的变体可以将最常用的组件(如
    )添加到生成器中。但是,执行扇入(如
    合并
    )或扇出(如
    广播
    )的连接操作必须显式传递给
    生成器。如果使用图形DSL,则添加

    请注意,对于简单的图形,您可以使用连接,而不必使用图形DSL。以下是来自以下方面的示例:

  • 这是什么意思?创建(TopHeadsLink,BottomHeadsLink)((,))
  • ((,))
    它是一个curried参数,指定要保留的具体化值。这里使用的
    ((,))
    与:

    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))
    的缩写,它保留传入的两个接收器的各自物化值。例如,如果只想保留
    topHeadSink
    的物化值,可以将调用更改为以下内容:

    val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, _) => t) {
      implicit builder => (topHS, bottomHS) =>
      ...
    }).run() // Future[Int]
    

    谢谢@chunjef!答案很好。对于
    sharedDoubler
    ,我还有一个问题,它没有经过
    create
    ,也没有在图中创建,它的物化值会发生什么变化?为什么我们有两种方法将图形传递到另一种?一个通过
    创建
    ,一个不创建?或者流不保留物化的值?所以您只需要通过
    创建
    添加源、汇?
    
    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)
    
    val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, b) => (t, b)) {
      implicit builder => (topHS, bottomHS) =>
      ...
    }).run() // (Future[Int], Future[Int])
    
    val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, _) => t) {
      implicit builder => (topHS, bottomHS) =>
      ...
    }).run() // Future[Int]