如何创建一个可以通过方法调用稍后接收元素的Source?

时间:2015-06-21 13:04:55

标签: scala akka akka-stream akka-http

我想在其上创建Source及更高版本的推送元素,例如:

val src = ... // create the Source here
// and then, do something like this
pushElement(x1, src)
pushElement(x2, src)

建议的方法是什么?

谢谢!

3 个答案:

答案 0 :(得分:86)

有三种方法可以实现:

<强> 1。使用SourceQueue发布实现

您可以使用awk '/Point/{exit 0} {print $NR}' file.txt 将流量转化为Source.queue

SourceQueue

<强> 2。使用Actor发布实现

有一个类似的问题和答案here,要点是你将流作为ActorRef实现并向该ref发送消息:

case class Weather(zipCode : String, temperature : Double, raining : Boolean)

val bufferSize = 100

//if the buffer fills up then this strategy drops the oldest elements
//upon the arrival of a new element.
val overflowStrategy = akka.stream.OverflowStrategy.dropHead

val queue = Source.queue(bufferSize, overflowStrategy)
                  .filter(!_.raining)
                  .to(Sink foreach println)
                  .run() // in order to "keep" the queue Materialized value instead of the Sink's

queue offer Weather("02139", 32.0, true)

第3。与演员预先实现

类似地,您可以显式创建一个包含消息缓冲区的Actor,使用该Actor创建一个Source,然后按照答案here中所述发送该Actor消息:

val ref = Source.actorRef[Weather](Int.MaxValue, fail)
                .filter(!_.raining)
                .to(Sink foreach println )
                .run() // in order to "keep" the ref Materialized value instead of the Sink's

ref ! Weather("02139", 32.0, true)

答案 1 :(得分:3)

在玩完并寻找一个很好的解决方案后,我遇到了这个简洁的解决方案,并且在前后实现方面都有效。 https://stackoverflow.com/a/32553913/6791842

Cannot delete or update a parent row: a foreign key constraint fails

输出:

  val (ref: ActorRef, publisher: Publisher[Int]) =
    Source.actorRef[Int](bufferSize = 1000, OverflowStrategy.fail)
      .toMat(Sink.asPublisher(true))(Keep.both).run()

  ref ! 1 //before

  val source = Source.fromPublisher(publisher)

  ref ! 2 //before
  Thread.sleep(1000)
  ref ! 3 //before

  source.runForeach(println)

  ref ! 4 //after
  Thread.sleep(1000)
  ref ! 5 //after

答案 2 :(得分:3)

由于Akka 2.5 Source具有preMaterialize方法。

根据documentation,这看起来像是您要执行的操作的指示方式:

  

在某些情况下,您需要Source的物化值,然后才能将Source连接到图的其余部分。对于“物化价值动力”来源(例如Source.queueSource.actorRefSource.maybe),这尤其有用。

下面是一个使用SourceQueue的示例。在实现之前和之后以及从Flow内部将元素推送到队列:

import akka.actor.ActorSystem
import akka.stream.scaladsl._
import akka.stream.{ActorMaterializer, OverflowStrategy}

implicit val system = ActorSystem("QuickStart")
implicit val materializer = ActorMaterializer()


val sourceDecl = Source.queue[String](bufferSize = 2, OverflowStrategy.backpressure)
val (sourceMat, source) = sourceDecl.preMaterialize()

// Adding element before actual materialization
sourceMat.offer("pre materialization element")

val flow = Flow[String].map { e =>
  if(!e.contains("new")) {
    // Adding elements from within the flow
    sourceMat.offer("new element generated inside the flow")
  }
  s"Processing $e"
}

// Actually materializing with `run`
source.via(flow).to(Sink.foreach(println)).run()

// Adding element after materialization
sourceMat.offer("post materialization element")

输出:

Processing pre materialization element
Processing post materialization element
Processing new element generated inside the flow
Processing new element generated inside the flow