我对这个正式托管的示例代码提出了几个问题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
})
create
传递图表?为什么topHeadSink, bottomHeadSink
通过create传入,但sharedDoubler
不是?他们之间有什么区别?
builder.add
?我可以在没有builder.add
的情况下在图表外创建广播吗?如果我在图中添加了几个流,我是否应该通过builder.add
添加流量?有时我们需要builder.add
,有时我们不需要,这是非常令人困惑的。
更新
我觉得这仍然令人困惑:
这些方法之间的区别在于使用builder.add(...)
导入会忽略导入图形的具体化值,而通过工厂方法导入则允许包含它。
topHS, bottomHS
是从create
导入的,因此他们会保留其物化价值。如果我builder.add(topHS)
怎么办?
你如何解释sharedDoubler
:它是否具有物化价值?如果我使用builder.add
怎么办?
((_,_))
的{{1}}?它看起来像我们需要的样板,但我不确定它是什么。
答案 0 :(得分:0)
- 您何时通过create?
传递图表 醇>
如果要获取传递给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
。
- 你什么时候需要builder.add?
醇>
图表的所有组件都必须添加到构建器中,但~>
运算符的变体添加了最常用的组件 - 例如Source
和{{1} - 给掩护下的建造者。但是,执行扇入(例如Flow
)或扇出(例如Merge
)的联结操作必须明确传递给Broadcast
如果您使用的是图形DSL。
请注意,对于简单的图形,您可以使用联结而无需使用Graph DSL。以下是documentation:
中的示例builder.add
- 这是什么意思?
醇>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}}?
这是一个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))