Scala Akka Streams中run()与runWith()的核心差异及适用场景
Akka Streams: run() 与 runWith() 的核心差异及适用场景
核心差异
1. 调用对象不同
run()是RunnableGraph的专属方法,必须在完整构建流拓扑(包括明确指定要保留的物化值)后才能调用。runWith()是Source或Flow的便捷方法,允许直接附加一个Sink并触发流的物化,无需先显式构建RunnableGraph。
2. 物化值控制不同
run()返回的是构建RunnableGraph时通过Keep类(如Keep.left、Keep.right、Keep.both)或自定义函数指定的物化值,可灵活选择保留源、Sink 或两者的物化值,甚至组合处理。runWith()默认返回附加的Sink的物化值,本质是source.toMat(sink)(Keep.right).run()的语法糖。
适用场景判断
使用 run() 的场景
- 需要保留
Source的物化值(例如Source.queue返回的队列引用),或同时保留源和 Sink 的物化值,或需要自定义组合两者的物化值。 - 构建了复杂流拓扑(包含多个
Flow、分支等),需要显式控制流的物化逻辑。
使用 runWith() 的场景
- 只关心
Sink的物化值,或完全不需要任何物化值(例如简单打印、写入文件等操作)。 - 编写简洁代码处理简单流场景:直接将
Source/Flow连接到单个 Sink,无需额外的物化值控制。
示例代码解析
给出的两段代码功能完全等价:
import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Keep, Sink, Source} object RunAndRunWith extends App { implicit val system: ActorSystem = ActorSystem("Run_RunWith") implicit val materializer: ActorMaterializer = ActorMaterializer() // 显式构建RunnableGraph,保留Sink的物化值后调用run() Source(1 to 10).toMat(Sink.foreach[Int](println))(Keep.right).run() // 使用runWith()快捷方式,效果与上面完全一致 Source(1 to 10).runWith(Sink.foreach[Int](println)) }
runWith(Sink) 就是 toMat(Sink)(Keep.right).run() 的缩写,两者都会物化流并执行 Sink.foreach 打印数字的操作,返回的都是 Sink.foreach 的物化值(这里是 Future[Done],表示流完成的信号)。
内容的提问来源于stack exchange,提问作者Always_a_learner
相关产品推荐
相关产品推荐

