为什么 Builder.add 应该用于路口而不是 GraphDSL.create 中的 Source/Flow/Sink?

Why Builder.add should be used for junctions but not for Source/Flow/Sink in GraphDSL.create?

akka-stream docs 中有一个关于如何使用 GraphDSL.create 构造非线性图形的示例。对于具有一个扇出元素的图形,最简单的代码示例如下:

val graph = GraphDSL.create(){implicit builder =>
  val source = Source(1 to 100)
  val flow = Flow.apply[Int]
  val sink1 = Sink.foreach[Int](println)
  val sink2 = Sink.foreach[Int](i => println("Sink2: " + i))
  val broadcast = builder.add(Broadcast[Int](2))
  source ~> flow ~> broadcast.in
  broadcast.out(0) ~> sink1
  broadcast.out(1) ~> sink2
  ClosedShape
}
RunnableGraph.fromGraph(graph).run()

我的问题是为什么 Broadcast 的实例在 builder.add 方法的帮助下应该是 'imported' 而对于 source/sink/flow 常规实例化就足够了?

如果我删除 builder.add 并只保留 val broadcast = Broadcast[Int](2) 那么代码将编译但在运行时将抛出异常:

Exception in thread "main" java.lang.IllegalArgumentException: [Broadcast.in] is already connected

文档没有清楚地解释这一点,只是按给定的方式提供。 你能澄清一下吗?

GraphDSL 允许您构建具有一系列有状态操作的图形,因此 所有 图形的各个阶段 必须被添加到构建器中。 builder.add操作returns一个阶段的Shape,这基本上就是它的蓝图。 Shape 可以与 ~> 组合器一起使用来组成图表。

但是,某些类型的阶段比其他阶段使用得更多(即 SourceSinkFlow),因此对于这些阶段,Akka 提供了方便的函数来添加它们作为 ~> 电话的一部分,为您联系建筑商。

查看 Akka 源代码中 this function and this function 之间的差异,以便更好地理解。这些是 Sink~> 函数。